From 64c7ee7e6b9c059d99aaa493c74a6703c6b0fc80 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 1 Jun 2011 18:28:20 +0200 Subject: [PATCH] CWallet class * A new class CKeyStore manages private keys, and script.cpp depends on access to CKeyStore. * A new class CWallet extends CKeyStore, and contains all former wallet-specific globals; CWallet depends on script.cpp, not the other way around. * Wallet-specific functions in CTransaction/CTxIn/CTxOut (GetDebit, GetCredit, GetChange, IsMine, IsFromMe), are moved to CWallet, taking their former 'this' argument as an explicit parameter * CWalletTx objects know which CWallet they belong to, for convenience, so they have their own direct (and caching) GetDebit/... functions. * Some code was moved from CWalletDB to CWallet, such as handling of reserve keys. * Main.cpp keeps a set of all 'registered' wallets, which should be informed about updates to the block chain, and does not have any notion about any 'main' wallet. Function in main.cpp that require a wallet (such as GenerateCoins), take an explicit CWallet* argument. * The actual CWallet instance used by the application is defined in init.cpp as "CWallet* pwalletMain". rpc.cpp and ui.cpp use this variable. * Functions in main.cpp and db.cpp that are not used by other modules are marked static. * The code for handling the 'submitorder' message is removed, as it not really compatible with the idea that a node is independent from the wallet(s) connected to it, and obsolete anyway. --- src/db.cpp | 65 ++++++++----- src/db.h | 94 +++++-------------- src/init.cpp | 22 +++-- src/init.h | 2 + src/keystore.cpp | 6 +- src/keystore.h | 20 ++++- src/main.cpp | 256 ++++++++++++++++++++++++++------------------------ src/main.h | 131 ++++++-------------------- src/net.cpp | 4 +- src/rpc.cpp | 148 +++++++++++++++--------------- src/script.cpp | 31 +++---- src/script.h | 7 +- src/ui.cpp | 186 ++++++++++++++++++------------------ src/wallet.cpp | 273 +++++++++++++++++++++++++++++++++-------------------- src/wallet.h | 248 +++++++++++++++++++++++++++++++++++++++++-------- 15 files changed, 829 insertions(+), 664 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 30e4bb0..d5405d7 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -10,8 +10,6 @@ using namespace std; using namespace boost; -void ThreadFlushWalletDB(void* parg); - unsigned int nWalletDBUpdated; uint64 nAccountingEntryNumber = 0; @@ -150,7 +148,7 @@ void CDB::Close() --mapFileUseCount[strFile]; } -void CloseDb(const string& strFile) +void static CloseDb(const string& strFile) { CRITICAL_BLOCK(cs_db) { @@ -359,7 +357,7 @@ bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork) return Write(string("bnBestInvalidWork"), bnBestInvalidWork); } -CBlockIndex* InsertBlockIndex(uint256 hash) +CBlockIndex static * InsertBlockIndex(uint256 hash) { if (hash == 0) return NULL; @@ -584,6 +582,20 @@ bool LoadAddresses() // CWalletDB // +bool CWalletDB::WriteName(const string& strAddress, const string& strName) +{ + nWalletDBUpdated++; + return Write(make_pair(string("name"), strAddress), strName); +} + +bool CWalletDB::EraseName(const string& strAddress) +{ + // 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. + nWalletDBUpdated++; + return Erase(make_pair(string("name"), strAddress)); +} + bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) { account.SetNull(); @@ -657,9 +669,9 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, listvchDefaultKey.clear(); int nFileVersion = 0; vector vWalletUpgrade; @@ -671,8 +683,8 @@ bool CWalletDB::LoadWallet() #endif //// todo: shouldn't we catch exceptions and try to recover and continue? - CRITICAL_BLOCK(cs_mapWallet) - CRITICAL_BLOCK(cs_mapKeys) + CRITICAL_BLOCK(pwallet->cs_mapWallet) + CRITICAL_BLOCK(pwallet->cs_mapKeys) { // Get cursor Dbc* pcursor = GetCursor(); @@ -699,14 +711,15 @@ bool CWalletDB::LoadWallet() { string strAddress; ssKey >> strAddress; - ssValue >> mapAddressBook[strAddress]; + ssValue >> pwallet->mapAddressBook[strAddress]; } else if (strType == "tx") { uint256 hash; ssKey >> hash; - CWalletTx& wtx = mapWallet[hash]; + CWalletTx& wtx = pwallet->mapWallet[hash]; ssValue >> wtx; + wtx.pwallet = pwallet; if (wtx.GetHash() != hash) printf("Error in wallet.dat, hash mismatch\n"); @@ -757,18 +770,18 @@ bool CWalletDB::LoadWallet() else ssValue >> wkey; - mapKeys[vchPubKey] = wkey.vchPrivKey; + pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey; mapPubKeys[Hash160(vchPubKey)] = vchPubKey; } else if (strType == "defaultkey") { - ssValue >> vchDefaultKey; + ssValue >> pwallet->vchDefaultKey; } else if (strType == "pool") { int64 nIndex; ssKey >> nIndex; - setKeyPool.insert(nIndex); + pwallet->setKeyPool.insert(nIndex); } else if (strType == "version") { @@ -800,7 +813,7 @@ bool CWalletDB::LoadWallet() } BOOST_FOREACH(uint256 hash, vWalletUpgrade) - WriteTx(hash, mapWallet[hash]); + WriteTx(hash, pwallet->mapWallet[hash]); printf("nFileVersion = %d\n", nFileVersion); printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); @@ -830,6 +843,7 @@ bool CWalletDB::LoadWallet() void ThreadFlushWalletDB(void* parg) { + const string& strFile = ((const string*)parg)[0]; static bool fOneThread; if (fOneThread) return; @@ -865,7 +879,6 @@ void ThreadFlushWalletDB(void* parg) if (nRefCount == 0 && !fShutdown) { - string strFile = "wallet.dat"; map::iterator mi = mapFileUseCount.find(strFile); if (mi != mapFileUseCount.end()) { @@ -888,26 +901,27 @@ void ThreadFlushWalletDB(void* parg) } } -void BackupWallet(const string& strDest) +bool BackupWallet(const CWallet& wallet, const string& strDest) { + if (!wallet.fFileBacked) + return false; while (!fShutdown) { CRITICAL_BLOCK(cs_db) { - const string strFile = "wallet.dat"; - if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) + if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0) { // Flush log data to the dat file - CloseDb(strFile); + CloseDb(wallet.strWalletFile); dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(strFile.c_str(), 0); - mapFileUseCount.erase(strFile); + dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0); + mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat - filesystem::path pathSrc(GetDataDir() + "/" + strFile); + filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile); filesystem::path pathDest(strDest); if (filesystem::is_directory(pathDest)) - pathDest = pathDest / strFile; + pathDest = pathDest / wallet.strWalletFile; #if BOOST_VERSION >= 104000 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); #else @@ -915,11 +929,10 @@ void BackupWallet(const string& strDest) #endif printf("copied wallet.dat to %s\n", pathDest.string().c_str()); - return; + return true; } } Sleep(100); } + return false; } - - diff --git a/src/db.h b/src/db.h index 5779837..b89b34e 100644 --- a/src/db.h +++ b/src/db.h @@ -12,33 +12,25 @@ #include -class CTransaction; class CTxIndex; class CDiskBlockIndex; class CDiskTxPos; class COutPoint; -class CUser; -class CReview; class CAddress; class CWalletTx; +class CWallet; class CAccount; class CAccountingEntry; class CBlockLocator; -extern std::vector vchDefaultKey; -extern bool fClient; -extern int nBestHeight; - extern unsigned int nWalletDBUpdated; extern DbEnv dbenv; extern void DBFlush(bool fShutdown); -extern std::vector GetKeyFromKeyPool(); -extern int64 GetOldestKeyPoolTime(); -extern void ThreadFlushWalletDB(void* parg); - +void ThreadFlushWalletDB(void* parg); +bool BackupWallet(const CWallet& wallet, const std::string& strDest); @@ -321,9 +313,6 @@ bool LoadAddresses(); - - - class CKeyPool { public: @@ -356,7 +345,7 @@ public: class CWalletDB : public CDB { public: - CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode) + CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode) { } private: @@ -369,23 +358,9 @@ public: return Read(std::make_pair(std::string("name"), strAddress), strName); } - bool WriteName(const std::string& strAddress, const std::string& strName) - { - CRITICAL_BLOCK(cs_mapAddressBook) - mapAddressBook[strAddress] = strName; - nWalletDBUpdated++; - return Write(std::make_pair(std::string("name"), strAddress), strName); - } + bool WriteName(const std::string& strAddress, const std::string& strName); - bool EraseName(const std::string& strAddress) - { - // 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. - CRITICAL_BLOCK(cs_mapAddressBook) - mapAddressBook.erase(strAddress); - nWalletDBUpdated++; - return Erase(std::make_pair(std::string("name"), strAddress)); - } + bool EraseName(const std::string& strAddress); bool ReadTx(uint256 hash, CWalletTx& wtx) { @@ -435,11 +410,27 @@ public: bool WriteDefaultKey(const std::vector& vchPubKey) { - vchDefaultKey = vchPubKey; nWalletDBUpdated++; return Write(std::string("defaultkey"), vchPubKey); } + bool ReadPool(int64 nPool, CKeyPool& keypool) + { + return Read(std::make_pair(std::string("pool"), nPool), keypool); + } + + bool WritePool(int64 nPool, const CKeyPool& keypool) + { + nWalletDBUpdated++; + return Write(std::make_pair(std::string("pool"), nPool), keypool); + } + + bool ErasePool(int64 nPool) + { + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("pool"), nPool)); + } + template bool ReadSetting(const std::string& strKey, T& value) { @@ -459,44 +450,7 @@ public: int64 GetAccountCreditDebit(const std::string& strAccount); void ListAccountCreditDebit(const std::string& strAccount, std::list& acentries); - bool LoadWallet(); -protected: - void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); - void KeepKey(int64 nIndex); - static void ReturnKey(int64 nIndex); - friend class CReserveKey; - friend std::vector GetKeyFromKeyPool(); - friend int64 GetOldestKeyPoolTime(); -}; - -bool LoadWallet(bool& fFirstRunRet); -void BackupWallet(const std::string& strDest); - -inline bool SetAddressBookName(const std::string& strAddress, const std::string& strName) -{ - return CWalletDB().WriteName(strAddress, strName); -} - -class CReserveKey -{ -protected: - int64 nIndex; - std::vector vchPubKey; -public: - CReserveKey() - { - nIndex = -1; - } - - ~CReserveKey() - { - if (!fShutdown) - ReturnKey(); - } - - std::vector GetReservedKey(); - void KeepKey(); - void ReturnKey(); + bool LoadWallet(CWallet* pwallet); }; #endif diff --git a/src/init.cpp b/src/init.cpp index b683e66..62bf169 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -13,6 +13,8 @@ using namespace std; using namespace boost; +CWallet* pwalletMain; + ////////////////////////////////////////////////////////////////////////////// // // Shutdown @@ -45,6 +47,8 @@ void Shutdown(void* parg) StopNode(); DBFlush(true); boost::filesystem::remove(GetPidFile()); + UnregisterWallet(pwalletMain); + delete pwalletMain; CreateThread(ExitTimeout, NULL); Sleep(50); printf("Bitcoin exiting\n\n"); @@ -372,16 +376,19 @@ bool AppInit2(int argc, char* argv[]) printf("Loading wallet...\n"); nStart = GetTimeMillis(); bool fFirstRun; - if (!LoadWallet(fFirstRun)) + pwalletMain = new CWallet("wallet.dat"); + if (!pwalletMain->LoadWallet(fFirstRun)) strErrors += _("Error loading wallet.dat \n"); printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); + RegisterWallet(pwalletMain); + CBlockIndex *pindexRescan = pindexBest; if (GetBoolArg("-rescan")) pindexRescan = pindexGenesisBlock; else { - CWalletDB walletdb; + CWalletDB walletdb("wallet.dat"); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) pindexRescan = locator.GetBlockIndex(); @@ -390,7 +397,7 @@ bool AppInit2(int argc, char* argv[]) { printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); - ScanForWalletTransactions(pindexRescan, true); + pwalletMain->ScanForWalletTransactions(pindexRescan, true); printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); } @@ -399,10 +406,11 @@ bool AppInit2(int argc, char* argv[]) //// debug print printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); printf("nBestHeight = %d\n", nBestHeight); - printf("mapKeys.size() = %d\n", mapKeys.size()); + printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size()); + printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size()); printf("mapPubKeys.size() = %d\n", mapPubKeys.size()); - printf("mapWallet.size() = %d\n", mapWallet.size()); - printf("mapAddressBook.size() = %d\n", mapAddressBook.size()); + printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size()); + printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size()); if (!strErrors.empty()) { @@ -411,7 +419,7 @@ bool AppInit2(int argc, char* argv[]) } // Add wallet transactions that aren't already in a block to mapTransactions - ReacceptWalletTransactions(); + pwalletMain->ReacceptWalletTransactions(); // // Parameters diff --git a/src/init.h b/src/init.h index 61b2728..a02260c 100644 --- a/src/init.h +++ b/src/init.h @@ -4,6 +4,8 @@ #ifndef BITCOIN_INIT_H #define BITCOIN_INIT_H +extern CWallet* pwalletMain; + void Shutdown(void* parg); bool AppInit(int argc, char* argv[]); bool AppInit2(int argc, char* argv[]); diff --git a/src/keystore.cpp b/src/keystore.cpp index 51f39a5..7dd045f 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -12,7 +12,7 @@ // mapKeys // -std::vector GenerateNewKey() +std::vector CKeyStore::GenerateNewKey() { RandAddSeedPerfmon(); CKey key; @@ -22,12 +22,12 @@ std::vector GenerateNewKey() return key.GetPubKey(); } -bool AddKey(const CKey& key) +bool CKeyStore::AddKey(const CKey& key) { CRITICAL_BLOCK(cs_mapKeys) { mapKeys[key.GetPubKey()] = key.GetPrivKey(); mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); } - return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey()); } + diff --git a/src/keystore.h b/src/keystore.h index 2f37ec5..3b6869b 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -4,7 +4,23 @@ #ifndef BITCOIN_KEYSTORE_H #define BITCOIN_KEYSTORE_H -bool AddKey(const CKey& key); -std::vector GenerateNewKey(); +class CKeyStore +{ +public: + std::map, CPrivKey> mapKeys; + mutable CCriticalSection cs_mapKeys; + virtual bool AddKey(const CKey& key); + bool HaveKey(const std::vector &vchPubKey) const + { + return (mapKeys.count(vchPubKey) > 0); + } + CPrivKey GetPrivKey(const std::vector &vchPubKey) const + { + std::map, CPrivKey>::const_iterator mi = mapKeys.find(vchPubKey); + if (mi != mapKeys.end()) + return (*mi).second; + } + std::vector GenerateNewKey(); +}; #endif diff --git a/src/main.cpp b/src/main.cpp index 8949b97..e3ec47d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,8 +15,14 @@ using namespace boost; // Global state // +CCriticalSection cs_setpwalletRegistered; +set setpwalletRegistered; + CCriticalSection cs_main; +CCriticalSection cs_mapPubKeys; +map > mapPubKeys; + map mapTransactions; CCriticalSection cs_mapTransactions; unsigned int nTransactionsUpdated = 0; @@ -39,25 +45,6 @@ multimap mapOrphanBlocksByPrev; map mapOrphanTransactions; multimap mapOrphanTransactionsByPrev; -map mapWallet; -vector vWalletUpdated; -CCriticalSection cs_mapWallet; - -map, CPrivKey> mapKeys; -map > mapPubKeys; -CCriticalSection cs_mapKeys; -CKey keyUser; - -map mapRequestCount; -CCriticalSection cs_mapRequestCount; - -map mapAddressBook; -CCriticalSection cs_mapAddressBook; - -set setKeyPool; -CCriticalSection cs_setKeyPool; - -vector vchDefaultKey; double dHashesPerSec; int64 nHPSTimerStart; @@ -84,10 +71,95 @@ int fUseUPnP = false; ////////////////////////////////////////////////////////////////////////////// // +// dispatching functions +// + +void RegisterWallet(CWallet* pwalletIn) +{ + CRITICAL_BLOCK(cs_setpwalletRegistered) + { + setpwalletRegistered.insert(pwalletIn); + } +} + +void UnregisterWallet(CWallet* pwalletIn) +{ + CRITICAL_BLOCK(cs_setpwalletRegistered) + { + setpwalletRegistered.erase(pwalletIn); + } +} + +bool static IsFromMe(CTransaction& tx) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + if (pwallet->IsFromMe(tx)) + return true; + return false; +} + +bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + if (pwallet->GetTransaction(hashTx,wtx)) + return true; + return false; +} + +void static EraseFromWallets(uint256 hash) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->EraseFromWallet(hash); +} + +void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate); +} + +void static SetBestChain(const CBlockLocator& loc) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->SetBestChain(loc); +} + +void static UpdatedTransaction(const uint256& hashTx) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->UpdatedTransaction(hashTx); +} + +void static PrintWallets(const CBlock& block) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->PrintWallet(block); +} + +void static Inventory(const uint256& hash) +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->Inventory(hash); +} + +void static ResendWalletTransactions() +{ + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + pwallet->ResendWalletTransactions(); +} + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// // mapOrphanTransactions // -void AddOrphanTx(const CDataStream& vMsg) +void static AddOrphanTx(const CDataStream& vMsg) { CTransaction tx; CDataStream(vMsg) >> tx; @@ -99,7 +171,7 @@ void AddOrphanTx(const CDataStream& vMsg) mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); } -void EraseOrphanTx(uint256 hash) +void static EraseOrphanTx(uint256 hash) { if (!mapOrphanTransactions.count(hash)) return; @@ -357,7 +429,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi nLastTime = nNow; // -limitfreerelay unit is thousand-bytes-per-minute // At default rate it would take over a month to fill 1GB - if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe()) + if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this)) return error("AcceptToMemoryPool() : free transaction rejected by rate limiter"); if (fDebug) printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); @@ -380,7 +452,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi ///// are we sure this is ok when loading transactions or restoring block txes // If updated, erase old tx from wallet if (ptxOld) - EraseFromWallet(ptxOld->GetHash()); + EraseFromWallets(ptxOld->GetHash()); printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str()); return true; @@ -551,8 +623,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions) return true; } - -uint256 GetOrphanRoot(const CBlock* pblock) +uint256 static GetOrphanRoot(const CBlock* pblock) { // Work back to the first block in the orphan chain while (mapOrphanBlocks.count(pblock->hashPrevBlock)) @@ -560,7 +631,7 @@ uint256 GetOrphanRoot(const CBlock* pblock) return pblock->GetHash(); } -int64 GetBlockValue(int nHeight, int64 nFees) +int64 static GetBlockValue(int nHeight, int64 nFees) { int64 nSubsidy = 50 * COIN; @@ -570,7 +641,7 @@ int64 GetBlockValue(int nHeight, int64 nFees) return nSubsidy + nFees; } -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast) +unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast) { const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks const int64 nTargetSpacing = 10 * 60; @@ -647,7 +718,7 @@ bool IsInitialBlockDownload() pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60); } -void InvalidChainFound(CBlockIndex* pindexNew) +void static InvalidChainFound(CBlockIndex* pindexNew) { if (pindexNew->bnChainWork > bnBestInvalidWork) { @@ -923,12 +994,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) // Watch for transactions paying to me BOOST_FOREACH(CTransaction& tx, vtx) - AddToWalletIfInvolvingMe(tx, this, true); + SyncWithWallets(tx, this, true); return true; } -bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) +bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) { printf("REORGANIZE\n"); @@ -1066,10 +1137,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) // Update best block in wallet (so we can detect restored wallets) if (!IsInitialBlockDownload()) { - CWalletDB walletdb; const CBlockLocator locator(pindexNew); - if (!walletdb.WriteBestBlock(locator)) - return error("SetBestChain() : WriteWalletBest failed"); + ::SetBestChain(locator); } // New best block @@ -1123,8 +1192,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) { // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; - CRITICAL_BLOCK(cs_mapWallet) - vWalletUpdated.push_back(hashPrevBestCoinBase); + UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = vtx[0].GetHash(); } @@ -1233,7 +1301,7 @@ bool CBlock::AcceptBlock() return true; } -bool ProcessBlock(CNode* pfrom, CBlock* pblock) +bool static ProcessBlock(CNode* pfrom, CBlock* pblock) { // Check for duplicate uint256 hash = pblock->GetHash(); @@ -1295,7 +1363,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) template -bool ScanMessageStart(Stream& s) +bool static ScanMessageStart(Stream& s) { // Scan ahead to the next pchMessageStart, which should normally be immediately // at the file pointer. Leaves file pointer at end of pchMessageStart. @@ -1510,7 +1578,7 @@ void PrintBlockTree() for (int i = 0; i < nCol; i++) printf("| "); printf("|\n"); - } + } nPrevCol = nCol; // print columns @@ -1528,16 +1596,7 @@ void PrintBlockTree() DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(), block.vtx.size()); - CRITICAL_BLOCK(cs_mapWallet) - { - if (mapWallet.count(block.vtx[0].GetHash())) - { - CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); - } - } - printf("\n"); - + PrintWallets(block); // put the main timechain first vector& vNext = mapNext[pindex]; @@ -1677,7 +1736,7 @@ bool CAlert::ProcessAlert() // -bool AlreadyHave(CTxDB& txdb, const CInv& inv) +bool static AlreadyHave(CTxDB& txdb, const CInv& inv) { switch (inv.type) { @@ -1697,7 +1756,7 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv) char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; -bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) +bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { static map > mapReuseKey; RandAddSeedPerfmon(); @@ -1894,12 +1953,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); // Track requests for our stuff - CRITICAL_BLOCK(cs_mapRequestCount) - { - map::iterator mi = mapRequestCount.find(inv.hash); - if (mi != mapRequestCount.end()) - (*mi).second++; - } + Inventory(inv.hash); } } @@ -1952,12 +2006,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Track requests for our stuff - CRITICAL_BLOCK(cs_mapRequestCount) - { - map::iterator mi = mapRequestCount.find(inv.hash); - if (mi != mapRequestCount.end()) - (*mi).second++; - } + Inventory(inv.hash); } } @@ -2045,7 +2094,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) bool fMissingInputs = false; if (tx.AcceptToMemoryPool(true, &fMissingInputs)) { - AddToWalletIfInvolvingMe(tx, NULL, true); + SyncWithWallets(tx, NULL, true); RelayMessage(inv, vMsg); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); @@ -2066,7 +2115,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (tx.AcceptToMemoryPool(true)) { printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); - AddToWalletIfInvolvingMe(tx, NULL, true); + SyncWithWallets(tx, NULL, true); RelayMessage(inv, vMsg); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); @@ -2143,7 +2192,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Keep giving the same key to the same ip until they use it if (!mapReuseKey.count(pfrom->addr.ip)) - mapReuseKey[pfrom->addr.ip] = GetKeyFromKeyPool(); + mapReuseKey[pfrom->addr.ip] = pwalletMain->GetKeyFromKeyPool(); // Send back approval of order and pubkey to use CScript scriptPubKey; @@ -2152,37 +2201,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } - else if (strCommand == "submitorder") - { - uint256 hashReply; - vRecv >> hashReply; - - if (!GetBoolArg("-allowreceivebyip")) - { - pfrom->PushMessage("reply", hashReply, (int)2); - return true; - } - - CWalletTx wtxNew; - vRecv >> wtxNew; - wtxNew.fFromMe = false; - - // Broadcast - if (!wtxNew.AcceptWalletTransaction()) - { - pfrom->PushMessage("reply", hashReply, (int)1); - return error("submitorder AcceptWalletTransaction() failed, returning error 1"); - } - wtxNew.fTimeReceivedIsTxTime = true; - AddToWallet(wtxNew); - wtxNew.RelayWalletTransaction(); - mapReuseKey.erase(pfrom->addr.ip); - - // Send back confirmation - pfrom->PushMessage("reply", hashReply, (int)0); - } - - else if (strCommand == "reply") { uint256 hashReply; @@ -2239,7 +2257,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) return true; } - bool ProcessMessages(CNode* pfrom) { CDataStream& vRecv = pfrom->vRecv; @@ -2359,8 +2376,6 @@ bool ProcessMessages(CNode* pfrom) } - - bool SendMessages(CNode* pto, bool fSendTrickle) { CRITICAL_BLOCK(cs_main) @@ -2483,16 +2498,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // always trickle our own transactions if (!fTrickleWait) { - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - map::iterator mi = mapWallet.find(inv.hash); - if (mi != mapWallet.end()) - { - CWalletTx& wtx = (*mi).second; - if (wtx.fFromMe) - fTrickleWait = true; - } - } + CWalletTx wtx; + if (GetTransaction(inv.hash, wtx)) + if (wtx.fFromMe) + fTrickleWait = true; } if (fTrickleWait) @@ -2565,7 +2574,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // BitcoinMiner // -int FormatHashBlocks(void* pbuffer, unsigned int len) +int static FormatHashBlocks(void* pbuffer, unsigned int len) { unsigned char* pdata = (unsigned char*)pbuffer; unsigned int blocks = 1 + ((len + 8) / 64); @@ -2598,7 +2607,7 @@ inline void SHA256Transform(void* pstate, void* pinput, const void* pinit) // between calls, but periodically or if nNonce is 0xffff0000 or above, // the block is rebuilt and nNonce starts over at zero. // -unsigned int ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) +unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) { unsigned int& nNonce = *(unsigned int*)(pdata + 12); for (;;) @@ -2855,7 +2864,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash } -bool CheckWork(CBlock* pblock, CReserveKey& reservekey) +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { uint256 hash = pblock->GetHash(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); @@ -2880,8 +2889,8 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey) reservekey.KeepKey(); // Track how many getdata requests this block gets - CRITICAL_BLOCK(cs_mapRequestCount) - mapRequestCount[pblock->GetHash()] = 0; + CRITICAL_BLOCK(wallet.cs_mapRequestCount) + wallet.mapRequestCount[pblock->GetHash()] = 0; // Process this block the same as if we had received it from another node if (!ProcessBlock(NULL, pblock)) @@ -2892,13 +2901,15 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey) return true; } -void BitcoinMiner() +void static ThreadBitcoinMiner(void* parg); + +void static BitcoinMiner(CWallet *pwallet) { printf("BitcoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); // Each thread has its own key and counter - CReserveKey reservekey; + CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; int64 nPrevTime = 0; @@ -2974,7 +2985,7 @@ void BitcoinMiner() assert(hash == pblock->GetHash()); SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock.get(), reservekey); + CheckWork(pblock.get(), *pwalletMain, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); break; } @@ -3035,12 +3046,13 @@ void BitcoinMiner() } } -void ThreadBitcoinMiner(void* parg) +void static ThreadBitcoinMiner(void* parg) { + CWallet* pwallet = (CWallet*)parg; try { vnThreadsRunning[3]++; - BitcoinMiner(); + BitcoinMiner(pwallet); vnThreadsRunning[3]--; } catch (std::exception& e) { @@ -3058,12 +3070,12 @@ void ThreadBitcoinMiner(void* parg) } -void GenerateBitcoins(bool fGenerate) +void GenerateBitcoins(bool fGenerate, CWallet* pwallet) { if (fGenerateBitcoins != fGenerate) { fGenerateBitcoins = fGenerate; - CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins); + WriteSetting("fGenerateBitcoins", fGenerateBitcoins); MainFrameRepaint(); } if (fGenerateBitcoins) @@ -3078,7 +3090,7 @@ void GenerateBitcoins(bool fGenerate) printf("Starting %d BitcoinMiner threads\n", nAddThreads); for (int i = 0; i < nAddThreads; i++) { - if (!CreateThread(ThreadBitcoinMiner, NULL)) + if (!CreateThread(ThreadBitcoinMiner, pwallet)) printf("Error: CreateThread(ThreadBitcoinMiner) failed\n"); Sleep(10); } diff --git a/src/main.h b/src/main.h index 2ebb8b8..3b35387 100644 --- a/src/main.h +++ b/src/main.h @@ -8,21 +8,17 @@ #include "net.h" #include "key.h" #include "script.h" +#include "db.h" #include -class COutPoint; -class CInPoint; -class CDiskTxPos; -class CCoinBase; -class CTxIn; -class CTxOut; -class CTransaction; class CBlock; class CBlockIndex; class CWalletTx; class CWallet; class CKeyItem; +class CReserveKey; +class CWalletDB; class CMessageHeader; class CAddress; @@ -62,15 +58,12 @@ extern CBigNum bnBestChainWork; extern CBigNum bnBestInvalidWork; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; -extern std::set setKeyPool; -extern CCriticalSection cs_setKeyPool; extern unsigned int nTransactionsUpdated; extern double dHashesPerSec; extern int64 nHPSTimerStart; extern int64 nTimeBestReceived; -extern std::map mapAddressBook; -extern CCriticalSection cs_mapAddressBook; - +extern CCriticalSection cs_setpwalletRegistered; +extern std::set setpwalletRegistered; // Settings extern int fGenerateBitcoins; @@ -90,21 +83,20 @@ class CReserveKey; class CTxDB; class CTxIndex; +void RegisterWallet(CWallet* pwalletIn); +void UnregisterWallet(CWallet* pwalletIn); bool CheckDiskSpace(uint64 nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* AppendBlockFile(unsigned int& nFileRet); bool LoadBlockIndex(bool fAllowNew=true); void PrintBlockTree(); bool ProcessMessages(CNode* pfrom); -bool ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vRecv); bool SendMessages(CNode* pto, bool fSendTrickle); -void GenerateBitcoins(bool fGenerate); -void ThreadBitcoinMiner(void* parg); +void GenerateBitcoins(bool fGenerate, CWallet* pwallet); CBlock* CreateNewBlock(CReserveKey& reservekey); void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime); void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); -bool CheckWork(CBlock* pblock, CReserveKey& reservekey); -void BitcoinMiner(); +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckProofOfWork(uint256 hash, unsigned int nBits); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); @@ -120,6 +112,23 @@ std::string GetWarnings(std::string strFor); +bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); + +template +bool WriteSetting(const std::string& strKey, const T& value) +{ + bool fOk = false; + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + { + std::string strWalletFile; + if (!GetWalletFile(pwallet, strWalletFile)) + continue; + fOk |= CWalletDB(strWalletFile).WriteSetting(strKey, value); + } + return fOk; +} + + class CDiskTxPos { public: @@ -302,9 +311,6 @@ public: { printf("%s\n", ToString().c_str()); } - - bool IsMine() const; - int64 GetDebit() const; }; @@ -353,36 +359,6 @@ public: return SerializeHash(*this); } - bool IsMine() const - { - return ::IsMine(scriptPubKey); - } - - int64 GetCredit() const - { - if (!MoneyRange(nValue)) - throw std::runtime_error("CTxOut::GetCredit() : value out of range"); - return (IsMine() ? nValue : 0); - } - - bool IsChange() const - { - // On a debit transaction, a txout that's mine but isn't in the address book is change - std::vector vchPubKey; - if (ExtractPubKey(scriptPubKey, true, vchPubKey)) - CRITICAL_BLOCK(cs_mapAddressBook) - if (!mapAddressBook.count(PubKeyToAddress(vchPubKey))) - return true; - return false; - } - - int64 GetChange() const - { - if (!MoneyRange(nValue)) - throw std::runtime_error("CTxOut::GetChange() : value out of range"); - return (IsChange() ? nValue : 0); - } - friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && @@ -527,57 +503,6 @@ public: return true; } - bool IsMine() const - { - BOOST_FOREACH(const CTxOut& txout, vout) - if (txout.IsMine()) - return true; - return false; - } - - bool IsFromMe() const - { - return (GetDebit() > 0); - } - - int64 GetDebit() const - { - int64 nDebit = 0; - BOOST_FOREACH(const CTxIn& txin, vin) - { - nDebit += txin.GetDebit(); - if (!MoneyRange(nDebit)) - throw std::runtime_error("CTransaction::GetDebit() : value out of range"); - } - return nDebit; - } - - int64 GetCredit() const - { - int64 nCredit = 0; - BOOST_FOREACH(const CTxOut& txout, vout) - { - nCredit += txout.GetCredit(); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CTransaction::GetCredit() : value out of range"); - } - return nCredit; - } - - int64 GetChange() const - { - if (IsCoinBase()) - return 0; - int64 nChange = 0; - BOOST_FOREACH(const CTxOut& txout, vout) - { - nChange += txout.GetChange(); - if (!MoneyRange(nChange)) - throw std::runtime_error("CTransaction::GetChange() : value out of range"); - } - return nChange; - } - int64 GetValueOut() const { int64 nValueOut = 0; @@ -1639,9 +1564,9 @@ public: + extern std::map mapTransactions; -extern std::map, CPrivKey> mapKeys; extern std::map > mapPubKeys; -extern CCriticalSection cs_mapKeys; +extern CCriticalSection cs_mapPubKeys; #endif diff --git a/src/net.cpp b/src/net.cpp index 8b439ef..4b13726 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1117,7 +1117,7 @@ void MapPort(bool fMapPort) if (fUseUPnP != fMapPort) { fUseUPnP = fMapPort; - CWalletDB().WriteSetting("fUseUPnP", fUseUPnP); + WriteSetting("fUseUPnP", fUseUPnP); } if (fUseUPnP && vnThreadsRunning[5] < 1) { @@ -1698,7 +1698,7 @@ void StartNode(void* parg) printf("Error: CreateThread(ThreadMessageHandler) failed\n"); // Generate coins in the background - GenerateBitcoins(fGenerateBitcoins); + GenerateBitcoins(fGenerateBitcoins, pwalletMain); } bool StopNode() diff --git a/src/rpc.cpp b/src/rpc.cpp index ad1abe3..5b395f9 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -264,14 +264,14 @@ Value setgenerate(const Array& params, bool fHelp) { int nGenProcLimit = params[1].get_int(); fLimitProcessors = (nGenProcLimit != -1); - CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors); + WriteSetting("fLimitProcessors", fLimitProcessors); if (nGenProcLimit != -1) - CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); + WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); if (nGenProcLimit == 0) fGenerate = false; } - GenerateBitcoins(fGenerate); + GenerateBitcoins(fGenerate, pwalletMain); return Value::null; } @@ -298,7 +298,7 @@ Value getinfo(const Array& params, bool fHelp) Object obj; obj.push_back(Pair("version", (int)VERSION)); - obj.push_back(Pair("balance", ValueFromAmount(GetBalance()))); + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("blocks", (int)nBestHeight)); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); @@ -307,7 +307,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("testnet", fTestNet)); - obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; @@ -329,9 +329,9 @@ Value getnewaddress(const Array& params, bool fHelp) strAccount = AccountFromValue(params[0]); // Generate a new key that is added to wallet - string strAddress = PubKeyToAddress(GetKeyFromKeyPool()); + string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool()); - SetAddressBookName(strAddress, strAccount); + pwalletMain->SetAddressBookName(strAddress, strAccount); return strAddress; } @@ -341,7 +341,7 @@ string GetAccountAddress(string strAccount, bool bForceNew=false) { string strAddress; - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); walletdb.TxnBegin(); CAccount account; @@ -352,8 +352,8 @@ string GetAccountAddress(string strAccount, bool bForceNew=false) { CScript scriptPubKey; scriptPubKey.SetBitcoinAddress(account.vchPubKey); - for (map::iterator it = mapWallet.begin(); - it != mapWallet.end() && !account.vchPubKey.empty(); + for (map::iterator it = pwalletMain->mapWallet.begin(); + it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty(); ++it) { const CWalletTx& wtx = (*it).second; @@ -366,9 +366,9 @@ string GetAccountAddress(string strAccount, bool bForceNew=false) // Generate a new key if (account.vchPubKey.empty() || bForceNew) { - account.vchPubKey = GetKeyFromKeyPool(); + account.vchPubKey = pwalletMain->GetKeyFromKeyPool(); string strAddress = PubKeyToAddress(account.vchPubKey); - SetAddressBookName(strAddress, strAccount); + pwalletMain->SetAddressBookName(strAddress, strAccount); walletdb.WriteAccount(strAccount, account); } @@ -391,7 +391,7 @@ Value getaccountaddress(const Array& params, bool fHelp) Value ret; CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { ret = GetAccountAddress(strAccount); } @@ -421,18 +421,18 @@ Value setaccount(const Array& params, bool fHelp) // Detect when changing the account of an address that is the 'unused current key' of another account: CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - if (mapAddressBook.count(strAddress)) + if (pwalletMain->mapAddressBook.count(strAddress)) { - string strOldAccount = mapAddressBook[strAddress]; + string strOldAccount = pwalletMain->mapAddressBook[strAddress]; if (strAddress == GetAccountAddress(strOldAccount)) GetAccountAddress(strOldAccount, true); } } - SetAddressBookName(strAddress, strAccount); + pwalletMain->SetAddressBookName(strAddress, strAccount); return Value::null; } @@ -447,10 +447,10 @@ Value getaccount(const Array& params, bool fHelp) string strAddress = params[0].get_str(); string strAccount; - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - map::iterator mi = mapAddressBook.find(strAddress); - if (mi != mapAddressBook.end() && !(*mi).second.empty()) + map::iterator mi = pwalletMain->mapAddressBook.find(strAddress); + if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) strAccount = (*mi).second; } return strAccount; @@ -468,9 +468,9 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) // Find all addresses that have the given account Array ret; - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { const string& strAddress = item.first; const string& strName = item.second; @@ -523,7 +523,7 @@ Value sendtoaddress(const Array& params, bool fHelp) CRITICAL_BLOCK(cs_main) { - string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); + string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); if (strError != "") throw JSONRPCError(-4, strError); } @@ -544,7 +544,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) CScript scriptPubKey; if (!scriptPubKey.SetBitcoinAddress(strAddress)) throw JSONRPCError(-5, "Invalid bitcoin address"); - if (!IsMine(scriptPubKey)) + if (!IsMine(*pwalletMain,scriptPubKey)) return (double)0.0; // Minimum confirmations @@ -554,9 +554,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) // Tally int64 nAmount = 0; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !wtx.IsFinal()) @@ -575,9 +575,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) void GetAccountPubKeys(string strAccount, set& setPubKey) { - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { const string& strAddress = item.first; const string& strName = item.second; @@ -586,7 +586,7 @@ void GetAccountPubKeys(string strAccount, set& setPubKey) // We're only counting our own valid bitcoin addresses and not ip addresses CScript scriptPubKey; if (scriptPubKey.SetBitcoinAddress(strAddress)) - if (IsMine(scriptPubKey)) + if (IsMine(*pwalletMain,scriptPubKey)) setPubKey.insert(scriptPubKey); } } @@ -613,9 +613,9 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) // Tally int64 nAmount = 0; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !wtx.IsFinal()) @@ -635,10 +635,10 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) { int64 nBalance = 0; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { // Tally wallet transactions - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!wtx.IsFinal()) @@ -661,7 +661,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD int64 GetAccountBalance(const string& strAccount, int nMinDepth) { - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); return GetAccountBalance(walletdb, strAccount, nMinDepth); } @@ -675,7 +675,7 @@ Value getbalance(const Array& params, bool fHelp) "If [account] is specified, returns the balance in the account."); if (params.size() == 0) - return ValueFromAmount(GetBalance()); + return ValueFromAmount(pwalletMain->GetBalance()); int nMinDepth = 1; if (params.size() > 1) @@ -686,7 +686,7 @@ Value getbalance(const Array& params, bool fHelp) // (GetBalance() sums up all unspent TxOuts) // getbalance and getbalance '*' should always return the same number. int64 nBalance = 0; - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!wtx.IsFinal()) @@ -734,9 +734,9 @@ Value movecmd(const Array& params, bool fHelp) if (params.size() > 4) strComment = params[4].get_str(); - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); walletdb.TxnBegin(); int64 nNow = GetAdjustedTime(); @@ -787,7 +787,7 @@ Value sendfrom(const Array& params, bool fHelp) wtx.mapValue["to"] = params[5].get_str(); CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { // Check funds int64 nBalance = GetAccountBalance(strAccount, nMinDepth); @@ -795,7 +795,7 @@ Value sendfrom(const Array& params, bool fHelp) throw JSONRPCError(-6, "Account has insufficient funds"); // Send - string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); + string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); if (strError != "") throw JSONRPCError(-4, strError); } @@ -844,7 +844,7 @@ Value sendmany(const Array& params, bool fHelp) } CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { // Check funds int64 nBalance = GetAccountBalance(strAccount, nMinDepth); @@ -852,16 +852,16 @@ Value sendmany(const Array& params, bool fHelp) throw JSONRPCError(-6, "Account has insufficient funds"); // Send - CReserveKey keyChange; + CReserveKey keyChange(pwalletMain); int64 nFeeRequired = 0; - bool fCreated = CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); + bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); if (!fCreated) { - if (totalAmount + nFeeRequired > GetBalance()) + if (totalAmount + nFeeRequired > pwalletMain->GetBalance()) throw JSONRPCError(-6, "Insufficient funds"); throw JSONRPCError(-4, "Transaction creation failed"); } - if (!CommitTransaction(wtx, keyChange)) + if (!pwalletMain->CommitTransaction(wtx, keyChange)) throw JSONRPCError(-4, "Transaction commit failed"); } @@ -894,9 +894,9 @@ Value ListReceived(const Array& params, bool fByAccounts) // Tally map mapTally; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !wtx.IsFinal()) @@ -923,9 +923,9 @@ Value ListReceived(const Array& params, bool fByAccounts) // Reply Array ret; map mapAccountTally; - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { const string& strAddress = item.first; const string& strAccount = item.second; @@ -1061,13 +1061,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived) { string account; - if (mapAddressBook.count(r.first)) - account = mapAddressBook[r.first]; + if (pwalletMain->mapAddressBook.count(r.first)) + account = pwalletMain->mapAddressBook[r.first]; if (fAllAccounts || (account == strAccount)) { Object entry; @@ -1119,16 +1119,16 @@ Value listtransactions(const Array& params, bool fHelp) nFrom = params[2].get_int(); Array ret; - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap: typedef pair TxPair; typedef multimap TxItems; TxItems txByTime; - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0))); @@ -1180,16 +1180,16 @@ Value listaccounts(const Array& params, bool fHelp) nMinDepth = params[0].get_int(); map mapAccountBalances; - CRITICAL_BLOCK(cs_mapWallet) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - BOOST_FOREACH(const PAIRTYPE(string, string)& entry, mapAddressBook) { + BOOST_FOREACH(const PAIRTYPE(string, string)& entry, pwalletMain->mapAddressBook) { uint160 hash160; if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me mapAccountBalances[entry.second] = 0; } - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; int64 nGeneratedImmature, nGeneratedMature, nFee; @@ -1204,8 +1204,8 @@ Value listaccounts(const Array& params, bool fHelp) { mapAccountBalances[""] += nGeneratedMature; BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived) - if (mapAddressBook.count(r.first)) - mapAccountBalances[mapAddressBook[r.first]] += r.second; + if (pwalletMain->mapAddressBook.count(r.first)) + mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; else mapAccountBalances[""] += r.second; } @@ -1213,7 +1213,7 @@ Value listaccounts(const Array& params, bool fHelp) } list acentries; - CWalletDB().ListAccountCreditDebit("*", acentries); + CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries); BOOST_FOREACH(const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; @@ -1235,11 +1235,11 @@ Value gettransaction(const Array& params, bool fHelp) hash.SetHex(params[0].get_str()); Object entry; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - if (!mapWallet.count(hash)) + if (!pwalletMain->mapWallet.count(hash)) throw JSONRPCError(-5, "Invalid or non-wallet transaction id"); - const CWalletTx& wtx = mapWallet[hash]; + const CWalletTx& wtx = pwalletMain->mapWallet[hash]; int64 nCredit = wtx.GetCredit(); int64 nDebit = wtx.GetDebit(); @@ -1250,10 +1250,10 @@ Value gettransaction(const Array& params, bool fHelp) if (wtx.IsFromMe()) entry.push_back(Pair("fee", ValueFromAmount(nFee))); - WalletTxToJSON(mapWallet[hash], entry); + WalletTxToJSON(pwalletMain->mapWallet[hash], entry); Array details; - ListTransactions(mapWallet[hash], "*", 0, false, details); + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); entry.push_back(Pair("details", details)); } @@ -1269,7 +1269,7 @@ Value backupwallet(const Array& params, bool fHelp) "Safely copies wallet.dat to destination, which can be a directory or a path with filename."); string strDest = params[0].get_str(); - BackupWallet(strDest); + BackupWallet(*pwalletMain, strDest); return Value::null; } @@ -1295,10 +1295,10 @@ Value validateaddress(const Array& params, bool fHelp) string currentAddress = Hash160ToAddress(hash160); ret.push_back(Pair("address", currentAddress)); ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0))); - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { - if (mapAddressBook.count(currentAddress)) - ret.push_back(Pair("account", mapAddressBook[currentAddress])); + if (pwalletMain->mapAddressBook.count(currentAddress)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[currentAddress])); } } return ret; @@ -1325,7 +1325,7 @@ Value getwork(const Array& params, bool fHelp) static map > mapNewBlock; static vector vNewBlock; - static CReserveKey reservekey; + static CReserveKey reservekey(pwalletMain); if (params.size() == 0) { @@ -1406,7 +1406,7 @@ Value getwork(const Array& params, bool fHelp) pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce); pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - return CheckWork(pblock, reservekey); + return CheckWork(pblock, *pwalletMain, reservekey); } } diff --git a/src/script.cpp b/src/script.cpp index 97334ca..e1b5ae8 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1021,7 +1021,7 @@ bool Solver(const CScript& scriptPubKey, vector >& vSo } -bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet) +bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet) { scriptSigRet.clear(); @@ -1030,7 +1030,7 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s return false; // Compile solution - CRITICAL_BLOCK(cs_mapKeys) + CRITICAL_BLOCK(keystore.cs_mapKeys) { BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) { @@ -1038,12 +1038,12 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s { // Sign const valtype& vchPubKey = item.second; - if (!mapKeys.count(vchPubKey)) + if (!keystore.HaveKey(vchPubKey)) return false; if (hash != 0) { vector vchSig; - if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig)) + if (!CKey::Sign(keystore.GetPrivKey(vchPubKey), hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); scriptSigRet << vchSig; @@ -1056,12 +1056,12 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s if (mi == mapPubKeys.end()) return false; const vector& vchPubKey = (*mi).second; - if (!mapKeys.count(vchPubKey)) + if (!keystore.HaveKey(vchPubKey)) return false; if (hash != 0) { vector vchSig; - if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig)) + if (!CKey::Sign(keystore.GetPrivKey(vchPubKey), hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); scriptSigRet << vchSig << vchPubKey; @@ -1085,14 +1085,14 @@ bool IsStandard(const CScript& scriptPubKey) } -bool IsMine(const CScript& scriptPubKey) +bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) { CScript scriptSig; - return Solver(scriptPubKey, 0, 0, scriptSig); + return Solver(keystore, scriptPubKey, 0, 0, scriptSig); } -bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector& vchPubKeyRet) +bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* keystore, vector& vchPubKeyRet) { vchPubKeyRet.clear(); @@ -1100,7 +1100,7 @@ bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vectorHaveKey(vchPubKey)) { vchPubKeyRet = vchPubKey; return true; @@ -1160,7 +1160,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C } -bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq) +bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; @@ -1171,7 +1171,7 @@ bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int // The checksig op will also drop the signatures from its hash. uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType); - if (!Solver(txout.scriptPubKey, hash, nHashType, txin.scriptSig)) + if (!Solver(keystore, txout.scriptPubKey, hash, nHashType, txin.scriptSig)) return false; txin.scriptSig = scriptPrereq + txin.scriptSig; @@ -1199,10 +1199,5 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType)) return false; - // Anytime a signature is successfully verified, it's proof the outpoint is spent, - // so lets update the wallet spent flag if it doesn't know due to wallet.dat being - // restored from backup or the user making copies of wallet.dat. - WalletUpdateSpent(txin.prevout); - return true; } diff --git a/src/script.h b/src/script.h index efafec4..ae9fdff 100644 --- a/src/script.h +++ b/src/script.h @@ -708,12 +708,11 @@ public: -uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); bool IsStandard(const CScript& scriptPubKey); -bool IsMine(const CScript& scriptPubKey); -bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, std::vector& vchPubKeyRet); +bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); +bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* pkeystore, std::vector& vchPubKeyRet); bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret); -bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript()); +bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript()); bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0); #endif diff --git a/src/ui.cpp b/src/ui.cpp index 72e8fe2..a49741f 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -240,7 +240,7 @@ void SetDefaultReceivingAddress(const string& strAddress) return; if (!mapPubKeys.count(hash160)) return; - CWalletDB().WriteDefaultKey(mapPubKeys[hash160]); + CWalletDB(pwalletMain->strWalletFile).WriteDefaultKey(mapPubKeys[hash160]); pframeMain->m_textCtrlAddress->SetValue(strAddress); } } @@ -290,7 +290,7 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent) dResize = 1.22; SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight()); #endif - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); + m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " "); m_listCtrl->SetFocus(); ptaskbaricon = new CMyTaskBarIcon(); #ifdef __WXMAC_OSX__ @@ -330,7 +330,7 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent) // Fill your address text box vector vchPubKey; - if (CWalletDB("r").ReadDefaultKey(vchPubKey)) + if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey)) m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey)); // Fill listctrl with wallet transactions @@ -625,7 +625,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) { int64 nUnmatured = 0; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - nUnmatured += txout.GetCredit(); + nUnmatured += pwalletMain->GetCredit(txout); if (wtx.IsInMainChain()) { strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); @@ -661,19 +661,19 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) return false; BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - if (txout.IsMine()) + if (pwalletMain->IsMine(txout)) { vector vchPubKey; - if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) + if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey)) { - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { //strDescription += _("Received payment to "); //strDescription += _("Received with address "); strDescription += _("Received with: "); string strAddress = PubKeyToAddress(vchPubKey); - map::iterator mi = mapAddressBook.find(strAddress); - if (mi != mapAddressBook.end() && !(*mi).second.empty()) + map::iterator mi = pwalletMain->mapAddressBook.find(strAddress); + if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) { string strLabel = (*mi).second; strDescription += strAddress.substr(0,12) + "... "; @@ -703,11 +703,11 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) - fAllFromMe = fAllFromMe && txin.IsMine(); + fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin); bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - fAllToMe = fAllToMe && txout.IsMine(); + fAllToMe = fAllToMe && pwalletMain->IsMine(txout); if (fAllFromMe && fAllToMe) { @@ -733,7 +733,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) for (int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; - if (txout.IsMine()) + if (pwalletMain->IsMine(txout)) continue; string strAddress; @@ -751,9 +751,9 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) } string strDescription = _("To: "); - CRITICAL_BLOCK(cs_mapAddressBook) - if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) - strDescription += mapAddressBook[strAddress] + " "; + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) + if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty()) + strDescription += pwalletMain->mapAddressBook[strAddress] + " "; strDescription += strAddress; if (!mapValue["message"].empty()) { @@ -792,9 +792,9 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) // bool fAllMine = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - fAllMine = fAllMine && txout.IsMine(); + fAllMine = fAllMine && pwalletMain->IsMine(txout); BOOST_FOREACH(const CTxIn& txin, wtx.vin) - fAllMine = fAllMine && txin.IsMine(); + fAllMine = fAllMine && pwalletMain->IsMine(txin); InsertLine(fNew, nIndex, hash, strSort, colour, strStatus, @@ -821,16 +821,16 @@ void CMainFrame::OnIdle(wxIdleEvent& event) // Collect list of wallet transactions and sort newest first bool fEntered = false; vector > vSorted; - TRY_CRITICAL_BLOCK(cs_mapWallet) + TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { printf("RefreshListCtrl starting\n"); fEntered = true; fRefreshListCtrl = false; - vWalletUpdated.clear(); + pwalletMain->vWalletUpdated.clear(); // Do the newest transactions first - vSorted.reserve(mapWallet.size()); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + vSorted.reserve(pwalletMain->mapWallet.size()); + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; unsigned int nTime = UINT_MAX - wtx.GetTxTime(); @@ -849,12 +849,12 @@ void CMainFrame::OnIdle(wxIdleEvent& event) if (fShutdown) return; bool fEntered = false; - TRY_CRITICAL_BLOCK(cs_mapWallet) + TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { fEntered = true; uint256& hash = vSorted[i++].second; - map::iterator mi = mapWallet.find(hash); - if (mi != mapWallet.end()) + map::iterator mi = pwalletMain->mapWallet.find(hash); + if (mi != pwalletMain->mapWallet.end()) InsertTransaction((*mi).second, true); } if (!fEntered || i == 100 || i % 500 == 0) @@ -872,10 +872,10 @@ void CMainFrame::OnIdle(wxIdleEvent& event) static int64 nLastTime; if (GetTime() > nLastTime + 30) { - TRY_CRITICAL_BLOCK(cs_mapWallet) + TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { nLastTime = GetTime(); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { CWalletTx& wtx = (*it).second; if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime()) @@ -896,7 +896,7 @@ void CMainFrame::RefreshStatusColumn() if (nTop == nLastTop && pindexLastBest == pindexBest) return; - TRY_CRITICAL_BLOCK(cs_mapWallet) + TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { int nStart = nTop; int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); @@ -916,8 +916,8 @@ void CMainFrame::RefreshStatusColumn() for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++) { uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); - map::iterator mi = mapWallet.find(hash); - if (mi == mapWallet.end()) + map::iterator mi = pwalletMain->mapWallet.find(hash); + if (mi == pwalletMain->mapWallet.end()) { printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n"); continue; @@ -1014,41 +1014,41 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) nLastRepaintTime = GetTimeMillis(); // Update listctrl contents - if (!vWalletUpdated.empty()) + if (!pwalletMain->vWalletUpdated.empty()) { - TRY_CRITICAL_BLOCK(cs_mapWallet) + TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { string strTop; if (m_listCtrl->GetItemCount()) strTop = (string)m_listCtrl->GetItemText(0); - BOOST_FOREACH(uint256 hash, vWalletUpdated) + BOOST_FOREACH(uint256 hash, pwalletMain->vWalletUpdated) { - map::iterator mi = mapWallet.find(hash); - if (mi != mapWallet.end()) + map::iterator mi = pwalletMain->mapWallet.find(hash); + if (mi != pwalletMain->mapWallet.end()) InsertTransaction((*mi).second, false); } - vWalletUpdated.clear(); + pwalletMain->vWalletUpdated.clear(); if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0)) m_listCtrl->ScrollList(0, INT_MIN/2); } } // Balance total - TRY_CRITICAL_BLOCK(cs_mapWallet) + TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { fPaintedBalance = true; - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); + m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " "); // Count hidden and multi-line transactions nTransactionCount = 0; - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { CWalletTx& wtx = (*it).second; nTransactionCount += wtx.nLinesDisplayed; } } } - if (!vWalletUpdated.empty() || !fPaintedBalance) + if (!pwalletMain->vWalletUpdated.empty() || !fPaintedBalance) nNeedRepaint++; // Update status column of visible items only @@ -1074,7 +1074,7 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) m_statusBar->SetStatusText(strStatus, 2); // Update receiving address - string strDefaultAddress = PubKeyToAddress(vchDefaultKey); + string strDefaultAddress = PubKeyToAddress(pwalletMain->vchDefaultKey); if (m_textCtrlAddress->GetValue() != strDefaultAddress) m_textCtrlAddress->SetValue(strDefaultAddress); } @@ -1183,10 +1183,10 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event) string strName = dialog.GetValue(); // Generate new key - string strAddress = PubKeyToAddress(GetKeyFromKeyPool()); + string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool()); // Save - SetAddressBookName(strAddress, strName); + pwalletMain->SetAddressBookName(strAddress, strName); SetDefaultReceivingAddress(strAddress); } @@ -1204,10 +1204,10 @@ void CMainFrame::OnListItemActivated(wxListEvent& event) { uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1)); CWalletTx wtx; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { - map::iterator mi = mapWallet.find(hash); - if (mi == mapWallet.end()) + map::iterator mi = pwalletMain->mapWallet.find(hash); + if (mi == pwalletMain->mapWallet.end()) { printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n"); return; @@ -1235,7 +1235,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails #ifdef __WXMSW__ SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight()); #endif - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { string strHTML; strHTML.reserve(4000); @@ -1285,19 +1285,19 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails // Credit BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - if (txout.IsMine()) + if (pwalletMain->IsMine(txout)) { vector vchPubKey; - if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) + if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey)) { string strAddress = PubKeyToAddress(vchPubKey); - if (mapAddressBook.count(strAddress)) + if (pwalletMain->mapAddressBook.count(strAddress)) { strHTML += string() + _("From: ") + _("unknown") + "
"; strHTML += _("To: "); strHTML += HtmlEscape(strAddress); - if (!mapAddressBook[strAddress].empty()) - strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")"; + if (!pwalletMain->mapAddressBook[strAddress].empty()) + strHTML += _(" (yours, label: ") + pwalletMain->mapAddressBook[strAddress] + ")"; else strHTML += _(" (yours)"); strHTML += "
"; @@ -1319,8 +1319,8 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails // Online transaction strAddress = wtx.mapValue["to"]; strHTML += _("To: "); - if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) - strHTML += mapAddressBook[strAddress] + " "; + if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty()) + strHTML += pwalletMain->mapAddressBook[strAddress] + " "; strHTML += HtmlEscape(strAddress) + "
"; } @@ -1335,7 +1335,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails // int64 nUnmatured = 0; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - nUnmatured += txout.GetCredit(); + nUnmatured += pwalletMain->GetCredit(txout); strHTML += _("Credit: "); if (wtx.IsInMainChain()) strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); @@ -1354,11 +1354,11 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) - fAllFromMe = fAllFromMe && txin.IsMine(); + fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin); bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - fAllToMe = fAllToMe && txout.IsMine(); + fAllToMe = fAllToMe && pwalletMain->IsMine(txout); if (fAllFromMe) { @@ -1367,7 +1367,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - if (txout.IsMine()) + if (pwalletMain->IsMine(txout)) continue; if (wtx.mapValue["to"].empty()) @@ -1378,8 +1378,8 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails { string strAddress = Hash160ToAddress(hash160); strHTML += _("To: "); - if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) - strHTML += mapAddressBook[strAddress] + " "; + if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty()) + strHTML += pwalletMain->mapAddressBook[strAddress] + " "; strHTML += strAddress; strHTML += "
"; } @@ -1407,11 +1407,11 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails // Mixed debit transaction // BOOST_FOREACH(const CTxIn& txin, wtx.vin) - if (txin.IsMine()) - strHTML += _("Debit: ") + FormatMoney(-txin.GetDebit()) + "
"; + if (pwalletMain->IsMine(txin)) + strHTML += _("Debit: ") + FormatMoney(-pwalletMain->GetDebit(txin)) + "
"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.IsMine()) - strHTML += _("Credit: ") + FormatMoney(txout.GetCredit()) + "
"; + if (pwalletMain->IsMine(txout)) + strHTML += _("Credit: ") + FormatMoney(pwalletMain->GetCredit(txout)) + "
"; } } @@ -1437,30 +1437,30 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails { strHTML += "

debug print

"; BOOST_FOREACH(const CTxIn& txin, wtx.vin) - if (txin.IsMine()) - strHTML += "Debit: " + FormatMoney(-txin.GetDebit()) + "
"; + if (pwalletMain->IsMine(txin)) + strHTML += "Debit: " + FormatMoney(-pwalletMain->GetDebit(txin)) + "
"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.IsMine()) - strHTML += "Credit: " + FormatMoney(txout.GetCredit()) + "
"; + if (pwalletMain->IsMine(txout)) + strHTML += "Credit: " + FormatMoney(pwalletMain->GetCredit(txout)) + "
"; strHTML += "
Transaction:
"; strHTML += HtmlEscape(wtx.ToString(), true); strHTML += "
Inputs:
"; - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwalletMain->cs_mapWallet) { BOOST_FOREACH(const CTxIn& txin, wtx.vin) { COutPoint prevout = txin.prevout; - map::iterator mi = mapWallet.find(prevout.hash); - if (mi != mapWallet.end()) + map::iterator mi = pwalletMain->mapWallet.find(prevout.hash); + if (mi != pwalletMain->mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (prevout.n < prev.vout.size()) { strHTML += HtmlEscape(prev.ToString(), true); strHTML += "    " + FormatTxStatus(prev) + ", "; - strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "
"; + strHTML = strHTML + "IsMine=" + (pwalletMain->IsMine(prev.vout[prevout.n]) ? "true" : "false") + "
"; } } } @@ -1751,7 +1751,7 @@ void COptionsDialog::OnButtonCancel(wxCommandEvent& event) void COptionsDialog::OnButtonApply(wxCommandEvent& event) { - CWalletDB walletdb; + CWalletDB walletdb(pwalletMain->strWalletFile); int64 nPrevTransactionFee = nTransactionFee; if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee) @@ -1928,12 +1928,12 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) wxMessageBox(_("Error in amount "), _("Send Coins")); return; } - if (nValue > GetBalance()) + if (nValue > pwalletMain->GetBalance()) { wxMessageBox(_("Amount exceeds your balance "), _("Send Coins")); return; } - if (nValue + nTransactionFee > GetBalance()) + if (nValue + nTransactionFee > pwalletMain->GetBalance()) { wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins")); return; @@ -1951,7 +1951,7 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) CScript scriptPubKey; scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; - string strError = SendMoney(scriptPubKey, nValue, wtx, true); + string strError = pwalletMain->SendMoney(scriptPubKey, nValue, wtx, true); if (strError == "") wxMessageBox(_("Payment sent "), _("Sending...")); else if (strError == "ABORTED") @@ -1983,9 +1983,9 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) return; } - CRITICAL_BLOCK(cs_mapAddressBook) - if (!mapAddressBook.count(strAddress)) - SetAddressBookName(strAddress, ""); + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) + if (!pwalletMain->mapAddressBook.count(strAddress)) + pwalletMain->SetAddressBookName(strAddress, ""); EndModal(true); } @@ -2169,7 +2169,7 @@ void SendingDialogStartTransfer(void* parg) void CSendingDialog::StartTransfer() { // Make sure we have enough money - if (nPrice + nTransactionFee > GetBalance()) + if (nPrice + nTransactionFee > pwalletMain->GetBalance()) { Error(_("Insufficient funds")); return; @@ -2240,16 +2240,16 @@ void CSendingDialog::OnReply2(CDataStream& vRecv) // Pay if (!Status(_("Creating transaction..."))) return; - if (nPrice + nTransactionFee > GetBalance()) + if (nPrice + nTransactionFee > pwalletMain->GetBalance()) { Error(_("Insufficient funds")); return; } - CReserveKey reservekey; + CReserveKey reservekey(pwalletMain); int64 nFeeRequired; - if (!CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired)) + if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired)) { - if (nPrice + nFeeRequired > GetBalance()) + if (nPrice + nFeeRequired > pwalletMain->GetBalance()) Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str())); else Error(_("Transaction creation failed")); @@ -2287,7 +2287,7 @@ void CSendingDialog::OnReply2(CDataStream& vRecv) return; // Commit - if (!CommitTransaction(wtx, reservekey)) + if (!pwalletMain->CommitTransaction(wtx, reservekey)) { 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; @@ -2381,11 +2381,11 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit m_listCtrlReceiving->SetFocus(); // Fill listctrl with address book data - CRITICAL_BLOCK(cs_mapKeys) - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwalletMain->cs_mapKeys) + CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) { string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue(); - BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook) { string strAddress = item.first; string strName = item.second; @@ -2444,7 +2444,7 @@ void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event) if (event.IsEditCancelled()) return; string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); - SetAddressBookName(strAddress, string(event.GetText())); + pwalletMain->SetAddressBookName(strAddress, string(event.GetText())); pframeMain->RefreshListCtrl(); } @@ -2479,7 +2479,7 @@ void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event) if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED)) { string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); - CWalletDB().EraseName(strAddress); + CWalletDB(pwalletMain->strWalletFile).EraseName(strAddress); m_listCtrl->DeleteItem(nIndex); } } @@ -2539,8 +2539,8 @@ void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event) // Write back if (strAddress != strAddressOrg) - CWalletDB().EraseName(strAddressOrg); - SetAddressBookName(strAddress, strName); + CWalletDB(pwalletMain->strWalletFile).EraseName(strAddressOrg); + pwalletMain->SetAddressBookName(strAddress, strName); m_listCtrl->SetItem(nIndex, 1, strAddress); m_listCtrl->SetItemText(nIndex, strName); pframeMain->RefreshListCtrl(); @@ -2576,11 +2576,11 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event) strName = dialog.GetValue(); // Generate new key - strAddress = PubKeyToAddress(GetKeyFromKeyPool()); + strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool()); } // Add to list and select it - SetAddressBookName(strAddress, strName); + pwalletMain->SetAddressBookName(strAddress, strName); int nIndex = InsertLine(m_listCtrl, strName, strAddress); SetSelection(m_listCtrl, nIndex); m_listCtrl->SetFocus(); diff --git a/src/wallet.cpp b/src/wallet.cpp index a9fc92f..aef8d18 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -15,29 +15,40 @@ using namespace std; // mapWallet // -void WalletUpdateSpent(const COutPoint& prevout) +bool CWallet::AddKey(const CKey& key) +{ + this->CKeyStore::AddKey(key); + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); +} + +void CWallet::WalletUpdateSpent(const CTransaction &tx) { // Anytime a signature is successfully verified, it's proof the outpoint is spent. // Update the wallet spent flag if it doesn't know due to wallet.dat being // restored from backup or the user making copies of wallet.dat. CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(prevout.hash); - if (mi != mapWallet.end()) + BOOST_FOREACH(const CTxIn& txin, tx.vin) { - CWalletTx& wtx = (*mi).second; - if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine()) + map::iterator mi = mapWallet.find(txin.prevout.hash); + if (mi != mapWallet.end()) { - printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); - wtx.MarkSpent(prevout.n); - wtx.WriteToDisk(); - vWalletUpdated.push_back(prevout.hash); + CWalletTx& wtx = (*mi).second; + if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) + { + printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); + wtx.MarkSpent(txin.prevout.n); + wtx.WriteToDisk(); + vWalletUpdated.push_back(txin.prevout.hash); + } } } } } -bool AddToWallet(const CWalletTx& wtxIn) +bool CWallet::AddToWallet(const CWalletTx& wtxIn) { uint256 hash = wtxIn.GetHash(); CRITICAL_BLOCK(cs_mapWallet) @@ -45,6 +56,7 @@ bool AddToWallet(const CWalletTx& wtxIn) // Inserts only if not already there, returns tx inserted or tx found pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; + wtx.pwallet = this; bool fInsertedNew = ret.second; if (fInsertedNew) wtx.nTimeReceived = GetAdjustedTime(); @@ -87,7 +99,9 @@ bool AddToWallet(const CWalletTx& wtxIn) { if (txout.scriptPubKey == scriptDefaultKey) { - CWalletDB walletdb; + if (!fFileBacked) + continue; + CWalletDB walletdb(strWalletFile); vchDefaultKey = GetKeyFromKeyPool(); walletdb.WriteDefaultKey(vchDefaultKey); walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); @@ -96,6 +110,9 @@ bool AddToWallet(const CWalletTx& wtxIn) // Notify UI vWalletUpdated.push_back(hash); + + // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins + WalletUpdateSpent(wtx); } // Refresh UI @@ -103,60 +120,64 @@ bool AddToWallet(const CWalletTx& wtxIn) return true; } -bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { uint256 hash = tx.GetHash(); bool fExisted = mapWallet.count(hash); if (fExisted && !fUpdate) return false; - if (fExisted || tx.IsMine() || tx.IsFromMe()) + if (fExisted || IsMine(tx) || IsFromMe(tx)) { - CWalletTx wtx(tx); + CWalletTx wtx(this,tx); // Get merkle branch if transaction was found in a block if (pblock) wtx.SetMerkleBranch(pblock); return AddToWallet(wtx); } + else + WalletUpdateSpent(tx); return false; } -bool EraseFromWallet(uint256 hash) +bool CWallet::EraseFromWallet(uint256 hash) { + if (!fFileBacked) + return false; CRITICAL_BLOCK(cs_mapWallet) { if (mapWallet.erase(hash)) - CWalletDB().EraseTx(hash); + CWalletDB(strWalletFile).EraseTx(hash); } return true; } -bool CTxIn::IsMine() const +bool CWallet::IsMine(const CTxIn &txin) const { CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(prevout.hash); + map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; - if (prevout.n < prev.vout.size()) - if (prev.vout[prevout.n].IsMine()) + if (txin.prevout.n < prev.vout.size()) + if (IsMine(prev.vout[txin.prevout.n])) return true; } } return false; } -int64 CTxIn::GetDebit() const +int64 CWallet::GetDebit(const CTxIn &txin) const { CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(prevout.hash); + map::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; - if (prevout.n < prev.vout.size()) - if (prev.vout[prevout.n].IsMine()) - return prev.vout[prevout.n].nValue; + if (txin.prevout.n < prev.vout.size()) + if (IsMine(prev.vout[txin.prevout.n])) + return prev.vout[txin.prevout.n].nValue; } } return 0; @@ -184,31 +205,31 @@ int CWalletTx::GetRequestCount() const { // Returns -1 if it wasn't being tracked int nRequests = -1; - CRITICAL_BLOCK(cs_mapRequestCount) + CRITICAL_BLOCK(pwallet->cs_mapRequestCount) { if (IsCoinBase()) { // Generated block if (hashBlock != 0) { - map::iterator mi = mapRequestCount.find(hashBlock); - if (mi != mapRequestCount.end()) + map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; } } else { // Did anyone request this transaction? - map::iterator mi = mapRequestCount.find(GetHash()); - if (mi != mapRequestCount.end()) + map::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); + if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; // How about the block it's in? if (nRequests == 0 && hashBlock != 0) { - map::iterator mi = mapRequestCount.find(hashBlock); - if (mi != mapRequestCount.end()) + map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; else nRequests = 1; // If it's in someone else's block it must have got out @@ -230,7 +251,7 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l if (IsCoinBase()) { if (GetBlocksToMaturity() > 0) - nGeneratedImmature = CTransaction::GetCredit(); + nGeneratedImmature = pwallet->GetCredit(*this); else nGeneratedMature = GetCredit(); return; @@ -263,13 +284,13 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l } // Don't report 'change' txouts - if (nDebit > 0 && txout.IsChange()) + if (nDebit > 0 && pwallet->IsChange(txout)) continue; if (nDebit > 0) listSent.push_back(make_pair(address, txout.nValue)); - if (txout.IsMine()) + if (pwallet->IsMine(txout)) listReceived.push_back(make_pair(address, txout.nValue)); } @@ -295,16 +316,15 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i nSent += s.second; nFee = allFee; } - CRITICAL_BLOCK(cs_mapAddressBook) + CRITICAL_BLOCK(pwallet->cs_mapAddressBook) { BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived) { - if (mapAddressBook.count(r.first)) + if (pwallet->mapAddressBook.count(r.first)) { - if (mapAddressBook[r.first] == strAccount) - { + map::const_iterator mi = pwallet->mapAddressBook.find(r.first); + if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount) nReceived += r.second; - } } else if (strAccount.empty()) { @@ -326,7 +346,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) vWorkQueue.push_back(txin.prevout.hash); // This critsect is OK because txdb is already open - CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(pwallet->cs_mapWallet) { map mapWalletPrev; set setAlreadyDone; @@ -338,10 +358,11 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) setAlreadyDone.insert(hash); CMerkleTx tx; - if (mapWallet.count(hash)) + map::const_iterator mi = pwallet->mapWallet.find(hash); + if (mi != pwallet->mapWallet.end()) { - tx = mapWallet[hash]; - BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev) + tx = (*mi).second; + BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev) mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev; } else if (mapWalletPrev.count(hash)) @@ -373,10 +394,10 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) bool CWalletTx::WriteToDisk() { - return CWalletDB().WriteTx(GetHash(), *this); + return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); } -int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) +int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { int ret = 0; @@ -398,7 +419,7 @@ int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) return ret; } -void ReacceptWalletTransactions() +void CWallet::ReacceptWalletTransactions() { CTxDB txdb("r"); bool fRepeat = true; @@ -426,7 +447,7 @@ void ReacceptWalletTransactions() { if (wtx.IsSpent(i)) continue; - if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine()) + if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i])) { wtx.MarkSpent(i); fUpdated = true; @@ -484,7 +505,7 @@ void CWalletTx::RelayWalletTransaction() RelayWalletTransaction(txdb); } -void ResendWalletTransactions() +void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away // that these are our transactions. @@ -536,16 +557,16 @@ void ResendWalletTransactions() // -int64 GetBalance() +int64 CWallet::GetBalance() const { int64 nStart = GetTimeMillis(); int64 nTotal = 0; CRITICAL_BLOCK(cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - CWalletTx* pcoin = &(*it).second; + const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) continue; nTotal += pcoin->GetAvailableCredit(); @@ -557,27 +578,27 @@ int64 GetBalance() } -bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set >& setCoinsRet, int64& nValueRet) +bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set >& setCoinsRet, int64& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target - pair > coinLowestLarger; + pair > coinLowestLarger; coinLowestLarger.first = INT64_MAX; coinLowestLarger.second.first = NULL; - vector > > vValue; + vector > > vValue; int64 nTotalLower = 0; CRITICAL_BLOCK(cs_mapWallet) { - vector vCoins; + vector vCoins; vCoins.reserve(mapWallet.size()); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) vCoins.push_back(&(*it).second); random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); - BOOST_FOREACH(CWalletTx* pcoin, vCoins) + BOOST_FOREACH(const CWalletTx* pcoin, vCoins) { if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) continue; @@ -591,7 +612,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< for (int i = 0; i < pcoin->vout.size(); i++) { - if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine()) + if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i])) continue; int64 n = pcoin->vout[i].nValue; @@ -599,7 +620,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< if (n <= 0) continue; - pair > coin = make_pair(n,make_pair(pcoin,i)); + pair > coin = make_pair(n,make_pair(pcoin,i)); if (n == nTargetValue) { @@ -702,7 +723,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set< return true; } -bool SelectCoins(int64 nTargetValue, set >& setCoinsRet, int64& nValueRet) +bool CWallet::SelectCoins(int64 nTargetValue, set >& setCoinsRet, int64& nValueRet) const { return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) || @@ -712,7 +733,7 @@ bool SelectCoins(int64 nTargetValue, set >& setCoi -bool CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { int64 nValue = 0; BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) @@ -724,6 +745,8 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& if (vecSend.empty() || nValue < 0) return false; + wtxNew.pwallet = this; + CRITICAL_BLOCK(cs_main) { // txdb must be opened before the mapWallet lock @@ -744,11 +767,11 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew.vout.push_back(CTxOut(s.second, s.first)); // Choose coins to use - set > setCoins; + set > setCoins; int64 nValueIn = 0; if (!SelectCoins(nTotalValue, setCoins, nValueIn)) return false; - BOOST_FOREACH(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins) + BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { int64 nCredit = pcoin.first->vout[pcoin.second].nValue; dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); @@ -784,13 +807,13 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& reservekey.ReturnKey(); // Fill vin - BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins) + 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(CWalletTx*,unsigned int)& coin, setCoins) - if (!SignSignature(*coin.first, wtxNew, nIn++)) + BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) + if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) return false; // Limit size @@ -820,7 +843,7 @@ bool CreateTransaction(const vector >& vecSend, CWalletTx& return true; } -bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) +bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { vector< pair > vecSend; vecSend.push_back(make_pair(scriptPubKey, nValue)); @@ -828,7 +851,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR } // Call after CreateTransaction unless you want to abort -bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) +bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { CRITICAL_BLOCK(cs_main) { @@ -838,7 +861,7 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // 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 walletdb("r"); + CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL; // Take key pair from key pool so it won't be used again reservekey.KeepKey(); @@ -851,11 +874,15 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) set setCoins; BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) { - CWalletTx &pcoin = mapWallet[txin.prevout.hash]; - pcoin.MarkSpent(txin.prevout.n); - pcoin.WriteToDisk(); - vWalletUpdated.push_back(pcoin.GetHash()); + CWalletTx &coin = mapWallet[txin.prevout.hash]; + coin.pwallet = this; + coin.MarkSpent(txin.prevout.n); + coin.WriteToDisk(); + vWalletUpdated.push_back(coin.GetHash()); } + + if (fFileBacked) + delete pwalletdb; } // Track how many getdata requests our transaction gets @@ -879,9 +906,9 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) // requires cs_main lock -string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { - CReserveKey reservekey; + CReserveKey reservekey(this); int64 nFeeRequired; if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) { @@ -907,7 +934,7 @@ string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAs // requires cs_main lock -string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { // Check amount if (nValue <= 0) @@ -926,10 +953,12 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx -bool LoadWallet(bool& fFirstRunRet) +bool CWallet::LoadWallet(bool& fFirstRunRet) { + if (!fFileBacked) + return false; fFirstRunRet = false; - if (!CWalletDB("cr+").LoadWallet()) + if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this)) return false; fFirstRunRet = vchDefaultKey.empty(); @@ -944,17 +973,52 @@ bool LoadWallet(bool& fFirstRunRet) // Create new keyUser and set as default key RandAddSeedPerfmon(); - CWalletDB walletdb; vchDefaultKey = GetKeyFromKeyPool(); - walletdb.WriteDefaultKey(vchDefaultKey); - walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); + if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), "")) + return false; + CWalletDB(strWalletFile).WriteDefaultKey(keyUser.GetPubKey()); } - CreateThread(ThreadFlushWalletDB, NULL); + CreateThread(ThreadFlushWalletDB, &strWalletFile); return true; } -void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) +void CWallet::PrintWallet(const CBlock& block) +{ + CRITICAL_BLOCK(cs_mapWallet) + { + if (mapWallet.count(block.vtx[0].GetHash())) + { + CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; + printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + } + } + printf("\n"); +} + +bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) +{ + CRITICAL_BLOCK(cs_mapWallet) + { + map::iterator mi = mapWallet.find(hashTx); + if (mi != mapWallet.end()) + { + wtx = (*mi).second; + return true; + } + return false; + } +} + +bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) +{ + if (!pwallet->fFileBacked) + return false; + strWalletFileOut = pwallet->strWalletFile; + return true; +} + +void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) { nIndex = -1; keypool.vchPubKey.clear(); @@ -962,6 +1026,8 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_setKeyPool) { + CWalletDB walletdb(strWalletFile); + // Top up key pool int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0); while (setKeyPool.size() < nTargetSize+1) @@ -969,7 +1035,7 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) int64 nEnd = 1; if (!setKeyPool.empty()) nEnd = *(--setKeyPool.end()) + 1; - if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey()))) + if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size()); @@ -979,7 +1045,7 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) assert(!setKeyPool.empty()); nIndex = *(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin()); - if (!Read(make_pair(string("pool"), nIndex), keypool)) + if (!walletdb.ReadPool(nIndex, keypool)) throw runtime_error("ReserveKeyFromKeyPool() : read failed"); if (!mapKeys.count(keypool.vchPubKey)) throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); @@ -988,18 +1054,21 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) } } -void CWalletDB::KeepKey(int64 nIndex) +void CWallet::KeepKey(int64 nIndex) { // Remove from key pool - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapWallet) + if (fFileBacked) { - Erase(make_pair(string("pool"), nIndex)); + CWalletDB walletdb(strWalletFile); + CRITICAL_BLOCK(cs_main) + { + walletdb.ErasePool(nIndex); + } } printf("keypool keep %"PRI64d"\n", nIndex); } -void CWalletDB::ReturnKey(int64 nIndex) +void CWallet::ReturnKey(int64 nIndex) { // Return to key pool CRITICAL_BLOCK(cs_setKeyPool) @@ -1007,32 +1076,30 @@ void CWalletDB::ReturnKey(int64 nIndex) printf("keypool return %"PRI64d"\n", nIndex); } -vector GetKeyFromKeyPool() +vector CWallet::GetKeyFromKeyPool() { - CWalletDB walletdb; int64 nIndex = 0; CKeyPool keypool; - walletdb.ReserveKeyFromKeyPool(nIndex, keypool); - walletdb.KeepKey(nIndex); + ReserveKeyFromKeyPool(nIndex, keypool); + KeepKey(nIndex); return keypool.vchPubKey; } -int64 GetOldestKeyPoolTime() +int64 CWallet::GetOldestKeyPoolTime() { - CWalletDB walletdb; int64 nIndex = 0; CKeyPool keypool; - walletdb.ReserveKeyFromKeyPool(nIndex, keypool); - walletdb.ReturnKey(nIndex); + ReserveKeyFromKeyPool(nIndex, keypool); + ReturnKey(nIndex); return keypool.nTime; } -std::vector CReserveKey::GetReservedKey() +vector CReserveKey::GetReservedKey() { if (nIndex == -1) { CKeyPool keypool; - CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool); + pwallet->ReserveKeyFromKeyPool(nIndex, keypool); vchPubKey = keypool.vchPubKey; } assert(!vchPubKey.empty()); @@ -1042,7 +1109,7 @@ std::vector CReserveKey::GetReservedKey() void CReserveKey::KeepKey() { if (nIndex != -1) - CWalletDB().KeepKey(nIndex); + pwallet->KeepKey(nIndex); nIndex = -1; vchPubKey.clear(); } @@ -1050,7 +1117,7 @@ void CReserveKey::KeepKey() void CReserveKey::ReturnKey() { if (nIndex != -1) - CWalletDB::ReturnKey(nIndex); + pwallet->ReturnKey(nIndex); nIndex = -1; vchPubKey.clear(); } diff --git a/src/wallet.h b/src/wallet.h index f9d2ea0..b14a2e8 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -5,40 +5,205 @@ #define BITCOIN_WALLET_H #include "bignum.h" +#include "key.h" #include "script.h" class CWalletTx; class CReserveKey; class CWalletDB; -extern std::map mapWallet; -extern std::vector vWalletUpdated; -extern CCriticalSection cs_mapWallet; +class CWallet : public CKeyStore +{ +private: + bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set >& setCoinsRet, int64& nValueRet) const; + bool SelectCoins(int64 nTargetValue, std::set >& setCoinsRet, int64& nValueRet) const; -extern std::map mapRequestCount; -extern CCriticalSection cs_mapRequestCount; -extern std::map mapAddressBook; -extern CCriticalSection cs_mapAddressBook; +public: + bool fFileBacked; + std::string strWalletFile; -extern std::vector vchDefaultKey; -extern CKey keyUser; + std::set setKeyPool; + CCriticalSection cs_setKeyPool; -bool AddToWallet(const CWalletTx& wtxIn); -bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); -bool EraseFromWallet(uint256 hash); -void WalletUpdateSpent(const COutPoint& prevout); -int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); -void ReacceptWalletTransactions(); -void ResendWalletTransactions(); -int64 GetBalance(); -bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); -bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); -bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); -bool BroadcastTransaction(CWalletTx& wtxNew); -std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); -std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); + CWallet() + { + fFileBacked = false; + } + CWallet(std::string strWalletFileIn) + { + strWalletFile = strWalletFileIn; + fFileBacked = true; + } + mutable CCriticalSection cs_mapWallet; + std::map mapWallet; + std::vector vWalletUpdated; + + std::map mapRequestCount; + mutable CCriticalSection cs_mapRequestCount; + + std::map mapAddressBook; + mutable CCriticalSection cs_mapAddressBook; + + std::vector vchDefaultKey; + CKey keyUser; + + bool AddKey(const CKey& key); + bool AddToWallet(const CWalletTx& wtxIn); + bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); + bool EraseFromWallet(uint256 hash); + void WalletUpdateSpent(const CTransaction& prevout); + int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); + void ReacceptWalletTransactions(); + void ResendWalletTransactions(); + int64 GetBalance() const; + bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); + bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); + bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); + bool BroadcastTransaction(CWalletTx& wtxNew); + std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); + std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); + + void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); + void KeepKey(int64 nIndex); + void ReturnKey(int64 nIndex); + std::vector GetKeyFromKeyPool(); + int64 GetOldestKeyPoolTime(); + + bool IsMine(const CTxIn& txin) const; + int64 GetDebit(const CTxIn& txin) const; + bool IsMine(const CTxOut& txout) const + { + return ::IsMine(*this, txout.scriptPubKey); + } + int64 GetCredit(const CTxOut& txout) const + { + if (!MoneyRange(txout.nValue)) + throw std::runtime_error("CWallet::GetCredit() : value out of range"); + return (IsMine(txout) ? txout.nValue : 0); + } + bool IsChange(const CTxOut& txout) const + { + std::vector vchPubKey; + if (ExtractPubKey(txout.scriptPubKey, this, vchPubKey)) + CRITICAL_BLOCK(cs_mapAddressBook) + if (!mapAddressBook.count(PubKeyToAddress(vchPubKey))) + return true; + return false; + } + int64 GetChange(const CTxOut& txout) const + { + if (!MoneyRange(txout.nValue)) + throw std::runtime_error("CWallet::GetChange() : value out of range"); + if (IsChange(txout) ? txout.nValue : 0); + } + bool IsMine(const CTransaction& tx) const + { + BOOST_FOREACH(const CTxOut& txout, tx.vout) + if (IsMine(txout)) + return true; + return false; + } + bool IsFromMe(const CTransaction& tx) const + { + return (GetDebit(tx) > 0); + } + int64 GetDebit(const CTransaction& tx) const + { + int64 nDebit = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + nDebit += GetDebit(txin); + if (!MoneyRange(nDebit)) + throw std::runtime_error("CWallet::GetDebit() : value out of range"); + } + return nDebit; + } + int64 GetCredit(const CTransaction& tx) const + { + int64 nCredit = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nCredit += GetCredit(txout); + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWallet::GetCredit() : value out of range"); + } + return nCredit; + } + int64 GetChange(const CTransaction& tx) const + { + int64 nChange = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nChange += GetChange(txout); + if (!MoneyRange(nChange)) + throw std::runtime_error("CWallet::GetChange() : value out of range"); + } + return nChange; + } + void SetBestChain(const CBlockLocator& loc) + { + CWalletDB walletdb(strWalletFile); + walletdb.WriteBestBlock(loc); + } + + bool LoadWallet(bool& fFirstRunRet); +// bool BackupWallet(const std::string& strDest); + + bool SetAddressBookName(const std::string& strAddress, const std::string& strName) + { + if (!fFileBacked) + return false; + return CWalletDB(strWalletFile).WriteName(strAddress, strName); + } + + void UpdatedTransaction(const uint256 &hashTx) + { + CRITICAL_BLOCK(cs_mapWallet) + vWalletUpdated.push_back(hashTx); + } + + void PrintWallet(const CBlock& block); + + void Inventory(const uint256 &hash) + { + CRITICAL_BLOCK(cs_mapRequestCount) + { + std::map::iterator mi = mapRequestCount.find(hash); + if (mi != mapRequestCount.end()) + (*mi).second++; + } + } + + bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); + +}; + + +class CReserveKey +{ +protected: + CWallet* pwallet; + int64 nIndex; + std::vector vchPubKey; +public: + CReserveKey(CWallet* pwalletIn) + { + nIndex = -1; + pwallet = pwalletIn; + } + + ~CReserveKey() + { + if (!fShutdown) + ReturnKey(); + } + + void ReturnKey(); + std::vector GetReservedKey(); + void KeepKey(); +}; // @@ -49,6 +214,8 @@ std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWal class CWalletTx : public CMerkleTx { public: + const CWallet* pwallet; + std::vector vtxPrev; std::map mapValue; std::vector > vOrderForm; @@ -73,24 +240,29 @@ public: mutable int nLinesDisplayed; mutable char fConfirmedDisplayed; - CWalletTx() { - Init(); + Init(NULL); } - CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn) + CWalletTx(const CWallet* pwalletIn) { - Init(); + Init(pwalletIn); } - CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn) + CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn) { - Init(); + Init(pwalletIn); } - void Init() + CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn) { + Init(pwalletIn); + } + + void Init(const CWallet* pwalletIn) + { + pwallet = pwalletIn; vtxPrev.clear(); mapValue.clear(); vOrderForm.clear(); @@ -116,7 +288,7 @@ public: ( CWalletTx* pthis = const_cast(this); if (fRead) - pthis->Init(); + pthis->Init(NULL); char fSpent = false; if (!fRead) @@ -213,7 +385,7 @@ public: return 0; if (fDebitCached) return nDebitCached; - nDebitCached = CTransaction::GetDebit(); + nDebitCached = pwallet->GetDebit(*this); fDebitCached = true; return nDebitCached; } @@ -227,7 +399,7 @@ public: // GetBalance can assume transactions in mapWallet won't change if (fUseCache && fCreditCached) return nCreditCached; - nCreditCached = CTransaction::GetCredit(); + nCreditCached = pwallet->GetCredit(*this); fCreditCached = true; return nCreditCached; } @@ -247,7 +419,7 @@ public: if (!IsSpent(i)) { const CTxOut &txout = vout[i]; - nCredit += txout.GetCredit(); + nCredit += pwallet->GetCredit(txout); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); } @@ -263,7 +435,7 @@ public: { if (fChangeCached) return nChangeCached; - nChangeCached = CTransaction::GetChange(); + nChangeCached = pwallet->GetChange(*this); fChangeCached = true; return nChangeCached; } @@ -271,7 +443,7 @@ public: void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list >& listReceived, std::list >& listSent, int64& nFee, std::string& strSentAccount) const; - void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, + void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, int64& nSent, int64& nFee) const; bool IsFromMe() const @@ -303,7 +475,7 @@ public: return false; if (ptx->GetDepthInMainChain() >= 1) continue; - if (!ptx->IsFromMe()) + if (!pwallet->IsFromMe(*ptx)) return false; if (mapPrev.empty()) @@ -438,4 +610,6 @@ public: ) }; +bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); + #endif -- 1.7.1