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.
This commit is contained in:
Pieter Wuille 2011-06-01 18:28:20 +02:00
parent e89b9f6a2a
commit 64c7ee7e6b
15 changed files with 829 additions and 664 deletions

View file

@ -10,8 +10,6 @@
using namespace std; using namespace std;
using namespace boost; using namespace boost;
void ThreadFlushWalletDB(void* parg);
unsigned int nWalletDBUpdated; unsigned int nWalletDBUpdated;
uint64 nAccountingEntryNumber = 0; uint64 nAccountingEntryNumber = 0;
@ -150,7 +148,7 @@ void CDB::Close()
--mapFileUseCount[strFile]; --mapFileUseCount[strFile];
} }
void CloseDb(const string& strFile) void static CloseDb(const string& strFile)
{ {
CRITICAL_BLOCK(cs_db) CRITICAL_BLOCK(cs_db)
{ {
@ -359,7 +357,7 @@ bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
return Write(string("bnBestInvalidWork"), bnBestInvalidWork); return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
} }
CBlockIndex* InsertBlockIndex(uint256 hash) CBlockIndex static * InsertBlockIndex(uint256 hash)
{ {
if (hash == 0) if (hash == 0)
return NULL; return NULL;
@ -584,6 +582,20 @@ bool LoadAddresses()
// CWalletDB // 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) bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
{ {
account.SetNull(); account.SetNull();
@ -657,9 +669,9 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
} }
bool CWalletDB::LoadWallet() bool CWalletDB::LoadWallet(CWallet* pwallet)
{ {
vchDefaultKey.clear(); pwallet->vchDefaultKey.clear();
int nFileVersion = 0; int nFileVersion = 0;
vector<uint256> vWalletUpgrade; vector<uint256> vWalletUpgrade;
@ -671,8 +683,8 @@ bool CWalletDB::LoadWallet()
#endif #endif
//// todo: shouldn't we catch exceptions and try to recover and continue? //// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwallet->cs_mapWallet)
CRITICAL_BLOCK(cs_mapKeys) CRITICAL_BLOCK(pwallet->cs_mapKeys)
{ {
// Get cursor // Get cursor
Dbc* pcursor = GetCursor(); Dbc* pcursor = GetCursor();
@ -699,14 +711,15 @@ bool CWalletDB::LoadWallet()
{ {
string strAddress; string strAddress;
ssKey >> strAddress; ssKey >> strAddress;
ssValue >> mapAddressBook[strAddress]; ssValue >> pwallet->mapAddressBook[strAddress];
} }
else if (strType == "tx") else if (strType == "tx")
{ {
uint256 hash; uint256 hash;
ssKey >> hash; ssKey >> hash;
CWalletTx& wtx = mapWallet[hash]; CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx; ssValue >> wtx;
wtx.pwallet = pwallet;
if (wtx.GetHash() != hash) if (wtx.GetHash() != hash)
printf("Error in wallet.dat, hash mismatch\n"); printf("Error in wallet.dat, hash mismatch\n");
@ -757,18 +770,18 @@ bool CWalletDB::LoadWallet()
else else
ssValue >> wkey; ssValue >> wkey;
mapKeys[vchPubKey] = wkey.vchPrivKey; pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey;
mapPubKeys[Hash160(vchPubKey)] = vchPubKey; mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
} }
else if (strType == "defaultkey") else if (strType == "defaultkey")
{ {
ssValue >> vchDefaultKey; ssValue >> pwallet->vchDefaultKey;
} }
else if (strType == "pool") else if (strType == "pool")
{ {
int64 nIndex; int64 nIndex;
ssKey >> nIndex; ssKey >> nIndex;
setKeyPool.insert(nIndex); pwallet->setKeyPool.insert(nIndex);
} }
else if (strType == "version") else if (strType == "version")
{ {
@ -800,7 +813,7 @@ bool CWalletDB::LoadWallet()
} }
BOOST_FOREACH(uint256 hash, vWalletUpgrade) BOOST_FOREACH(uint256 hash, vWalletUpgrade)
WriteTx(hash, mapWallet[hash]); WriteTx(hash, pwallet->mapWallet[hash]);
printf("nFileVersion = %d\n", nFileVersion); printf("nFileVersion = %d\n", nFileVersion);
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
@ -830,6 +843,7 @@ bool CWalletDB::LoadWallet()
void ThreadFlushWalletDB(void* parg) void ThreadFlushWalletDB(void* parg)
{ {
const string& strFile = ((const string*)parg)[0];
static bool fOneThread; static bool fOneThread;
if (fOneThread) if (fOneThread)
return; return;
@ -865,7 +879,6 @@ void ThreadFlushWalletDB(void* parg)
if (nRefCount == 0 && !fShutdown) if (nRefCount == 0 && !fShutdown)
{ {
string strFile = "wallet.dat";
map<string, int>::iterator mi = mapFileUseCount.find(strFile); map<string, int>::iterator mi = mapFileUseCount.find(strFile);
if (mi != mapFileUseCount.end()) 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) while (!fShutdown)
{ {
CRITICAL_BLOCK(cs_db) CRITICAL_BLOCK(cs_db)
{ {
const string strFile = "wallet.dat"; if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
{ {
// Flush log data to the dat file // Flush log data to the dat file
CloseDb(strFile); CloseDb(wallet.strWalletFile);
dbenv.txn_checkpoint(0, 0, 0); dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(strFile.c_str(), 0); dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
mapFileUseCount.erase(strFile); mapFileUseCount.erase(wallet.strWalletFile);
// Copy wallet.dat // Copy wallet.dat
filesystem::path pathSrc(GetDataDir() + "/" + strFile); filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
filesystem::path pathDest(strDest); filesystem::path pathDest(strDest);
if (filesystem::is_directory(pathDest)) if (filesystem::is_directory(pathDest))
pathDest = pathDest / strFile; pathDest = pathDest / wallet.strWalletFile;
#if BOOST_VERSION >= 104000 #if BOOST_VERSION >= 104000
filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists); filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
#else #else
@ -915,11 +929,10 @@ void BackupWallet(const string& strDest)
#endif #endif
printf("copied wallet.dat to %s\n", pathDest.string().c_str()); printf("copied wallet.dat to %s\n", pathDest.string().c_str());
return; return true;
} }
} }
Sleep(100); Sleep(100);
} }
return false;
} }

View file

@ -12,33 +12,25 @@
#include <db_cxx.h> #include <db_cxx.h>
class CTransaction;
class CTxIndex; class CTxIndex;
class CDiskBlockIndex; class CDiskBlockIndex;
class CDiskTxPos; class CDiskTxPos;
class COutPoint; class COutPoint;
class CUser;
class CReview;
class CAddress; class CAddress;
class CWalletTx; class CWalletTx;
class CWallet;
class CAccount; class CAccount;
class CAccountingEntry; class CAccountingEntry;
class CBlockLocator; class CBlockLocator;
extern std::vector<unsigned char> vchDefaultKey;
extern bool fClient;
extern int nBestHeight;
extern unsigned int nWalletDBUpdated; extern unsigned int nWalletDBUpdated;
extern DbEnv dbenv; extern DbEnv dbenv;
extern void DBFlush(bool fShutdown); extern void DBFlush(bool fShutdown);
extern std::vector<unsigned char> GetKeyFromKeyPool(); void ThreadFlushWalletDB(void* parg);
extern int64 GetOldestKeyPoolTime(); bool BackupWallet(const CWallet& wallet, const std::string& strDest);
extern void ThreadFlushWalletDB(void* parg);
@ -321,9 +313,6 @@ bool LoadAddresses();
class CKeyPool class CKeyPool
{ {
public: public:
@ -356,7 +345,7 @@ public:
class CWalletDB : public CDB class CWalletDB : public CDB
{ {
public: public:
CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode) CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
{ {
} }
private: private:
@ -369,23 +358,9 @@ public:
return Read(std::make_pair(std::string("name"), strAddress), strName); return Read(std::make_pair(std::string("name"), strAddress), strName);
} }
bool WriteName(const std::string& strAddress, const std::string& 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 EraseName(const std::string& strAddress) 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 ReadTx(uint256 hash, CWalletTx& wtx) bool ReadTx(uint256 hash, CWalletTx& wtx)
{ {
@ -435,11 +410,27 @@ public:
bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey) bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
{ {
vchDefaultKey = vchPubKey;
nWalletDBUpdated++; nWalletDBUpdated++;
return Write(std::string("defaultkey"), vchPubKey); 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<typename T> template<typename T>
bool ReadSetting(const std::string& strKey, T& value) bool ReadSetting(const std::string& strKey, T& value)
{ {
@ -459,44 +450,7 @@ public:
int64 GetAccountCreditDebit(const std::string& strAccount); int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
bool LoadWallet(); bool LoadWallet(CWallet* pwallet);
protected:
void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
void KeepKey(int64 nIndex);
static void ReturnKey(int64 nIndex);
friend class CReserveKey;
friend std::vector<unsigned char> 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<unsigned char> vchPubKey;
public:
CReserveKey()
{
nIndex = -1;
}
~CReserveKey()
{
if (!fShutdown)
ReturnKey();
}
std::vector<unsigned char> GetReservedKey();
void KeepKey();
void ReturnKey();
}; };
#endif #endif

View file

@ -13,6 +13,8 @@
using namespace std; using namespace std;
using namespace boost; using namespace boost;
CWallet* pwalletMain;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Shutdown // Shutdown
@ -45,6 +47,8 @@ void Shutdown(void* parg)
StopNode(); StopNode();
DBFlush(true); DBFlush(true);
boost::filesystem::remove(GetPidFile()); boost::filesystem::remove(GetPidFile());
UnregisterWallet(pwalletMain);
delete pwalletMain;
CreateThread(ExitTimeout, NULL); CreateThread(ExitTimeout, NULL);
Sleep(50); Sleep(50);
printf("Bitcoin exiting\n\n"); printf("Bitcoin exiting\n\n");
@ -372,16 +376,19 @@ bool AppInit2(int argc, char* argv[])
printf("Loading wallet...\n"); printf("Loading wallet...\n");
nStart = GetTimeMillis(); nStart = GetTimeMillis();
bool fFirstRun; bool fFirstRun;
if (!LoadWallet(fFirstRun)) pwalletMain = new CWallet("wallet.dat");
if (!pwalletMain->LoadWallet(fFirstRun))
strErrors += _("Error loading wallet.dat \n"); strErrors += _("Error loading wallet.dat \n");
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
CBlockIndex *pindexRescan = pindexBest; CBlockIndex *pindexRescan = pindexBest;
if (GetBoolArg("-rescan")) if (GetBoolArg("-rescan"))
pindexRescan = pindexGenesisBlock; pindexRescan = pindexGenesisBlock;
else else
{ {
CWalletDB walletdb; CWalletDB walletdb("wallet.dat");
CBlockLocator locator; CBlockLocator locator;
if (walletdb.ReadBestBlock(locator)) if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex(); 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); printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis(); nStart = GetTimeMillis();
ScanForWalletTransactions(pindexRescan, true); pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
} }
@ -399,10 +406,11 @@ bool AppInit2(int argc, char* argv[])
//// debug print //// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size()); printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight); 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("mapPubKeys.size() = %d\n", mapPubKeys.size());
printf("mapWallet.size() = %d\n", mapWallet.size()); printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
printf("mapAddressBook.size() = %d\n", mapAddressBook.size()); printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
if (!strErrors.empty()) 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 // Add wallet transactions that aren't already in a block to mapTransactions
ReacceptWalletTransactions(); pwalletMain->ReacceptWalletTransactions();
// //
// Parameters // Parameters

View file

@ -4,6 +4,8 @@
#ifndef BITCOIN_INIT_H #ifndef BITCOIN_INIT_H
#define BITCOIN_INIT_H #define BITCOIN_INIT_H
extern CWallet* pwalletMain;
void Shutdown(void* parg); void Shutdown(void* parg);
bool AppInit(int argc, char* argv[]); bool AppInit(int argc, char* argv[]);
bool AppInit2(int argc, char* argv[]); bool AppInit2(int argc, char* argv[]);

View file

@ -12,7 +12,7 @@
// mapKeys // mapKeys
// //
std::vector<unsigned char> GenerateNewKey() std::vector<unsigned char> CKeyStore::GenerateNewKey()
{ {
RandAddSeedPerfmon(); RandAddSeedPerfmon();
CKey key; CKey key;
@ -22,12 +22,12 @@ std::vector<unsigned char> GenerateNewKey()
return key.GetPubKey(); return key.GetPubKey();
} }
bool AddKey(const CKey& key) bool CKeyStore::AddKey(const CKey& key)
{ {
CRITICAL_BLOCK(cs_mapKeys) CRITICAL_BLOCK(cs_mapKeys)
{ {
mapKeys[key.GetPubKey()] = key.GetPrivKey(); mapKeys[key.GetPubKey()] = key.GetPrivKey();
mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey(); mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
} }
return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey());
} }

View file

@ -4,7 +4,23 @@
#ifndef BITCOIN_KEYSTORE_H #ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H #define BITCOIN_KEYSTORE_H
bool AddKey(const CKey& key); class CKeyStore
std::vector<unsigned char> GenerateNewKey(); {
public:
std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
mutable CCriticalSection cs_mapKeys;
virtual bool AddKey(const CKey& key);
bool HaveKey(const std::vector<unsigned char> &vchPubKey) const
{
return (mapKeys.count(vchPubKey) > 0);
}
CPrivKey GetPrivKey(const std::vector<unsigned char> &vchPubKey) const
{
std::map<std::vector<unsigned char>, CPrivKey>::const_iterator mi = mapKeys.find(vchPubKey);
if (mi != mapKeys.end())
return (*mi).second;
}
std::vector<unsigned char> GenerateNewKey();
};
#endif #endif

View file

@ -15,8 +15,14 @@ using namespace boost;
// Global state // Global state
// //
CCriticalSection cs_setpwalletRegistered;
set<CWallet*> setpwalletRegistered;
CCriticalSection cs_main; CCriticalSection cs_main;
CCriticalSection cs_mapPubKeys;
map<uint160, vector<unsigned char> > mapPubKeys;
map<uint256, CTransaction> mapTransactions; map<uint256, CTransaction> mapTransactions;
CCriticalSection cs_mapTransactions; CCriticalSection cs_mapTransactions;
unsigned int nTransactionsUpdated = 0; unsigned int nTransactionsUpdated = 0;
@ -39,25 +45,6 @@ multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions; map<uint256, CDataStream*> mapOrphanTransactions;
multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev; multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
map<uint256, CWalletTx> mapWallet;
vector<uint256> vWalletUpdated;
CCriticalSection cs_mapWallet;
map<vector<unsigned char>, CPrivKey> mapKeys;
map<uint160, vector<unsigned char> > mapPubKeys;
CCriticalSection cs_mapKeys;
CKey keyUser;
map<uint256, int> mapRequestCount;
CCriticalSection cs_mapRequestCount;
map<string, string> mapAddressBook;
CCriticalSection cs_mapAddressBook;
set<int64> setKeyPool;
CCriticalSection cs_setKeyPool;
vector<unsigned char> vchDefaultKey;
double dHashesPerSec; double dHashesPerSec;
int64 nHPSTimerStart; int64 nHPSTimerStart;
@ -82,12 +69,97 @@ 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 // mapOrphanTransactions
// //
void AddOrphanTx(const CDataStream& vMsg) void static AddOrphanTx(const CDataStream& vMsg)
{ {
CTransaction tx; CTransaction tx;
CDataStream(vMsg) >> tx; CDataStream(vMsg) >> tx;
@ -99,7 +171,7 @@ void AddOrphanTx(const CDataStream& vMsg)
mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
} }
void EraseOrphanTx(uint256 hash) void static EraseOrphanTx(uint256 hash)
{ {
if (!mapOrphanTransactions.count(hash)) if (!mapOrphanTransactions.count(hash))
return; return;
@ -357,7 +429,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
nLastTime = nNow; nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute // -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB // 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"); return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
if (fDebug) if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); 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 ///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet // If updated, erase old tx from wallet
if (ptxOld) if (ptxOld)
EraseFromWallet(ptxOld->GetHash()); EraseFromWallets(ptxOld->GetHash());
printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str()); printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
return true; return true;
@ -551,8 +623,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
return true; return true;
} }
uint256 static GetOrphanRoot(const CBlock* pblock)
uint256 GetOrphanRoot(const CBlock* pblock)
{ {
// Work back to the first block in the orphan chain // Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock)) while (mapOrphanBlocks.count(pblock->hashPrevBlock))
@ -560,7 +631,7 @@ uint256 GetOrphanRoot(const CBlock* pblock)
return pblock->GetHash(); return pblock->GetHash();
} }
int64 GetBlockValue(int nHeight, int64 nFees) int64 static GetBlockValue(int nHeight, int64 nFees)
{ {
int64 nSubsidy = 50 * COIN; int64 nSubsidy = 50 * COIN;
@ -570,7 +641,7 @@ int64 GetBlockValue(int nHeight, int64 nFees)
return nSubsidy + 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 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
const int64 nTargetSpacing = 10 * 60; const int64 nTargetSpacing = 10 * 60;
@ -647,7 +718,7 @@ bool IsInitialBlockDownload()
pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60); pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
} }
void InvalidChainFound(CBlockIndex* pindexNew) void static InvalidChainFound(CBlockIndex* pindexNew)
{ {
if (pindexNew->bnChainWork > bnBestInvalidWork) if (pindexNew->bnChainWork > bnBestInvalidWork)
{ {
@ -923,12 +994,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// Watch for transactions paying to me // Watch for transactions paying to me
BOOST_FOREACH(CTransaction& tx, vtx) BOOST_FOREACH(CTransaction& tx, vtx)
AddToWalletIfInvolvingMe(tx, this, true); SyncWithWallets(tx, this, true);
return true; return true;
} }
bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{ {
printf("REORGANIZE\n"); 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) // Update best block in wallet (so we can detect restored wallets)
if (!IsInitialBlockDownload()) if (!IsInitialBlockDownload())
{ {
CWalletDB walletdb;
const CBlockLocator locator(pindexNew); const CBlockLocator locator(pindexNew);
if (!walletdb.WriteBestBlock(locator)) ::SetBestChain(locator);
return error("SetBestChain() : WriteWalletBest failed");
} }
// New best block // 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 // Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase; static uint256 hashPrevBestCoinBase;
CRITICAL_BLOCK(cs_mapWallet) UpdatedTransaction(hashPrevBestCoinBase);
vWalletUpdated.push_back(hashPrevBestCoinBase);
hashPrevBestCoinBase = vtx[0].GetHash(); hashPrevBestCoinBase = vtx[0].GetHash();
} }
@ -1233,7 +1301,7 @@ bool CBlock::AcceptBlock()
return true; return true;
} }
bool ProcessBlock(CNode* pfrom, CBlock* pblock) bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
{ {
// Check for duplicate // Check for duplicate
uint256 hash = pblock->GetHash(); uint256 hash = pblock->GetHash();
@ -1295,7 +1363,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
template<typename Stream> template<typename Stream>
bool ScanMessageStart(Stream& s) bool static ScanMessageStart(Stream& s)
{ {
// Scan ahead to the next pchMessageStart, which should normally be immediately // Scan ahead to the next pchMessageStart, which should normally be immediately
// at the file pointer. Leaves file pointer at end of pchMessageStart. // at the file pointer. Leaves file pointer at end of pchMessageStart.
@ -1510,7 +1578,7 @@ void PrintBlockTree()
for (int i = 0; i < nCol; i++) for (int i = 0; i < nCol; i++)
printf("| "); printf("| ");
printf("|\n"); printf("|\n");
} }
nPrevCol = nCol; nPrevCol = nCol;
// print columns // print columns
@ -1528,16 +1596,7 @@ void PrintBlockTree()
DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(), DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size()); block.vtx.size());
CRITICAL_BLOCK(cs_mapWallet) PrintWallets(block);
{
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");
// put the main timechain first // put the main timechain first
vector<CBlockIndex*>& vNext = mapNext[pindex]; vector<CBlockIndex*>& 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) switch (inv.type)
{ {
@ -1697,7 +1756,7 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv)
char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 }; 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<unsigned int, vector<unsigned char> > mapReuseKey; static map<unsigned int, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon(); RandAddSeedPerfmon();
@ -1894,12 +1953,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff // Track requests for our stuff
CRITICAL_BLOCK(cs_mapRequestCount) Inventory(inv.hash);
{
map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
} }
} }
@ -1952,12 +2006,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
} }
// Track requests for our stuff // Track requests for our stuff
CRITICAL_BLOCK(cs_mapRequestCount) Inventory(inv.hash);
{
map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
} }
} }
@ -2045,7 +2094,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool fMissingInputs = false; bool fMissingInputs = false;
if (tx.AcceptToMemoryPool(true, &fMissingInputs)) if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{ {
AddToWalletIfInvolvingMe(tx, NULL, true); SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg); RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv); mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash); vWorkQueue.push_back(inv.hash);
@ -2066,7 +2115,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (tx.AcceptToMemoryPool(true)) if (tx.AcceptToMemoryPool(true))
{ {
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); 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); RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv); mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash); 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 // Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip)) 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 // Send back approval of order and pubkey to use
CScript scriptPubKey; 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") else if (strCommand == "reply")
{ {
uint256 hashReply; uint256 hashReply;
@ -2239,7 +2257,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true; return true;
} }
bool ProcessMessages(CNode* pfrom) bool ProcessMessages(CNode* pfrom)
{ {
CDataStream& vRecv = pfrom->vRecv; CDataStream& vRecv = pfrom->vRecv;
@ -2359,8 +2376,6 @@ bool ProcessMessages(CNode* pfrom)
} }
bool SendMessages(CNode* pto, bool fSendTrickle) bool SendMessages(CNode* pto, bool fSendTrickle)
{ {
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
@ -2483,16 +2498,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// always trickle our own transactions // always trickle our own transactions
if (!fTrickleWait) if (!fTrickleWait)
{ {
TRY_CRITICAL_BLOCK(cs_mapWallet) CWalletTx wtx;
{ if (GetTransaction(inv.hash, wtx))
map<uint256, CWalletTx>::iterator mi = mapWallet.find(inv.hash); if (wtx.fFromMe)
if (mi != mapWallet.end()) fTrickleWait = true;
{
CWalletTx& wtx = (*mi).second;
if (wtx.fFromMe)
fTrickleWait = true;
}
}
} }
if (fTrickleWait) if (fTrickleWait)
@ -2565,7 +2574,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// BitcoinMiner // BitcoinMiner
// //
int FormatHashBlocks(void* pbuffer, unsigned int len) int static FormatHashBlocks(void* pbuffer, unsigned int len)
{ {
unsigned char* pdata = (unsigned char*)pbuffer; unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64); 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, // between calls, but periodically or if nNonce is 0xffff0000 or above,
// the block is rebuilt and nNonce starts over at zero. // 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); unsigned int& nNonce = *(unsigned int*)(pdata + 12);
for (;;) 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 hash = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
@ -2880,8 +2889,8 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
reservekey.KeepKey(); reservekey.KeepKey();
// Track how many getdata requests this block gets // Track how many getdata requests this block gets
CRITICAL_BLOCK(cs_mapRequestCount) CRITICAL_BLOCK(wallet.cs_mapRequestCount)
mapRequestCount[pblock->GetHash()] = 0; wallet.mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node // Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock)) if (!ProcessBlock(NULL, pblock))
@ -2892,13 +2901,15 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
return true; return true;
} }
void BitcoinMiner() void static ThreadBitcoinMiner(void* parg);
void static BitcoinMiner(CWallet *pwallet)
{ {
printf("BitcoinMiner started\n"); printf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST); SetThreadPriority(THREAD_PRIORITY_LOWEST);
// Each thread has its own key and counter // Each thread has its own key and counter
CReserveKey reservekey; CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0; unsigned int nExtraNonce = 0;
int64 nPrevTime = 0; int64 nPrevTime = 0;
@ -2974,7 +2985,7 @@ void BitcoinMiner()
assert(hash == pblock->GetHash()); assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL); SetThreadPriority(THREAD_PRIORITY_NORMAL);
CheckWork(pblock.get(), reservekey); CheckWork(pblock.get(), *pwalletMain, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST); SetThreadPriority(THREAD_PRIORITY_LOWEST);
break; break;
} }
@ -3035,12 +3046,13 @@ void BitcoinMiner()
} }
} }
void ThreadBitcoinMiner(void* parg) void static ThreadBitcoinMiner(void* parg)
{ {
CWallet* pwallet = (CWallet*)parg;
try try
{ {
vnThreadsRunning[3]++; vnThreadsRunning[3]++;
BitcoinMiner(); BitcoinMiner(pwallet);
vnThreadsRunning[3]--; vnThreadsRunning[3]--;
} }
catch (std::exception& e) { 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) if (fGenerateBitcoins != fGenerate)
{ {
fGenerateBitcoins = fGenerate; fGenerateBitcoins = fGenerate;
CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins); WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
MainFrameRepaint(); MainFrameRepaint();
} }
if (fGenerateBitcoins) if (fGenerateBitcoins)
@ -3078,7 +3090,7 @@ void GenerateBitcoins(bool fGenerate)
printf("Starting %d BitcoinMiner threads\n", nAddThreads); printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++) for (int i = 0; i < nAddThreads; i++)
{ {
if (!CreateThread(ThreadBitcoinMiner, NULL)) if (!CreateThread(ThreadBitcoinMiner, pwallet))
printf("Error: CreateThread(ThreadBitcoinMiner) failed\n"); printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
Sleep(10); Sleep(10);
} }

View file

@ -8,21 +8,17 @@
#include "net.h" #include "net.h"
#include "key.h" #include "key.h"
#include "script.h" #include "script.h"
#include "db.h"
#include <list> #include <list>
class COutPoint;
class CInPoint;
class CDiskTxPos;
class CCoinBase;
class CTxIn;
class CTxOut;
class CTransaction;
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
class CWalletTx; class CWalletTx;
class CWallet; class CWallet;
class CKeyItem; class CKeyItem;
class CReserveKey;
class CWalletDB;
class CMessageHeader; class CMessageHeader;
class CAddress; class CAddress;
@ -62,15 +58,12 @@ extern CBigNum bnBestChainWork;
extern CBigNum bnBestInvalidWork; extern CBigNum bnBestInvalidWork;
extern uint256 hashBestChain; extern uint256 hashBestChain;
extern CBlockIndex* pindexBest; extern CBlockIndex* pindexBest;
extern std::set<int64> setKeyPool;
extern CCriticalSection cs_setKeyPool;
extern unsigned int nTransactionsUpdated; extern unsigned int nTransactionsUpdated;
extern double dHashesPerSec; extern double dHashesPerSec;
extern int64 nHPSTimerStart; extern int64 nHPSTimerStart;
extern int64 nTimeBestReceived; extern int64 nTimeBestReceived;
extern std::map<std::string, std::string> mapAddressBook; extern CCriticalSection cs_setpwalletRegistered;
extern CCriticalSection cs_mapAddressBook; extern std::set<CWallet*> setpwalletRegistered;
// Settings // Settings
extern int fGenerateBitcoins; extern int fGenerateBitcoins;
@ -90,21 +83,20 @@ class CReserveKey;
class CTxDB; class CTxDB;
class CTxIndex; class CTxIndex;
void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
bool CheckDiskSpace(uint64 nAdditionalBytes=0); bool CheckDiskSpace(uint64 nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet); FILE* AppendBlockFile(unsigned int& nFileRet);
bool LoadBlockIndex(bool fAllowNew=true); bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree(); void PrintBlockTree();
bool ProcessMessages(CNode* pfrom); bool ProcessMessages(CNode* pfrom);
bool ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vRecv);
bool SendMessages(CNode* pto, bool fSendTrickle); bool SendMessages(CNode* pto, bool fSendTrickle);
void GenerateBitcoins(bool fGenerate); void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
void ThreadBitcoinMiner(void* parg);
CBlock* CreateNewBlock(CReserveKey& reservekey); CBlock* CreateNewBlock(CReserveKey& reservekey);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime); void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
bool CheckWork(CBlock* pblock, CReserveKey& reservekey); bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
void BitcoinMiner();
bool CheckProofOfWork(uint256 hash, unsigned int nBits); bool CheckProofOfWork(uint256 hash, unsigned int nBits);
bool IsInitialBlockDownload(); bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor); std::string GetWarnings(std::string strFor);
@ -120,6 +112,23 @@ std::string GetWarnings(std::string strFor);
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
template<typename T>
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 class CDiskTxPos
{ {
public: public:
@ -302,9 +311,6 @@ public:
{ {
printf("%s\n", ToString().c_str()); printf("%s\n", ToString().c_str());
} }
bool IsMine() const;
int64 GetDebit() const;
}; };
@ -353,36 +359,6 @@ public:
return SerializeHash(*this); 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<unsigned char> 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) friend bool operator==(const CTxOut& a, const CTxOut& b)
{ {
return (a.nValue == b.nValue && return (a.nValue == b.nValue &&
@ -527,57 +503,6 @@ public:
return true; 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 GetValueOut() const
{ {
int64 nValueOut = 0; int64 nValueOut = 0;
@ -1639,9 +1564,9 @@ public:
extern std::map<uint256, CTransaction> mapTransactions; extern std::map<uint256, CTransaction> mapTransactions;
extern std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
extern std::map<uint160, std::vector<unsigned char> > mapPubKeys; extern std::map<uint160, std::vector<unsigned char> > mapPubKeys;
extern CCriticalSection cs_mapKeys; extern CCriticalSection cs_mapPubKeys;
#endif #endif

View file

@ -1117,7 +1117,7 @@ void MapPort(bool fMapPort)
if (fUseUPnP != fMapPort) if (fUseUPnP != fMapPort)
{ {
fUseUPnP = fMapPort; fUseUPnP = fMapPort;
CWalletDB().WriteSetting("fUseUPnP", fUseUPnP); WriteSetting("fUseUPnP", fUseUPnP);
} }
if (fUseUPnP && vnThreadsRunning[5] < 1) if (fUseUPnP && vnThreadsRunning[5] < 1)
{ {
@ -1698,7 +1698,7 @@ void StartNode(void* parg)
printf("Error: CreateThread(ThreadMessageHandler) failed\n"); printf("Error: CreateThread(ThreadMessageHandler) failed\n");
// Generate coins in the background // Generate coins in the background
GenerateBitcoins(fGenerateBitcoins); GenerateBitcoins(fGenerateBitcoins, pwalletMain);
} }
bool StopNode() bool StopNode()

View file

@ -264,14 +264,14 @@ Value setgenerate(const Array& params, bool fHelp)
{ {
int nGenProcLimit = params[1].get_int(); int nGenProcLimit = params[1].get_int();
fLimitProcessors = (nGenProcLimit != -1); fLimitProcessors = (nGenProcLimit != -1);
CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors); WriteSetting("fLimitProcessors", fLimitProcessors);
if (nGenProcLimit != -1) if (nGenProcLimit != -1)
CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit); WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
if (nGenProcLimit == 0) if (nGenProcLimit == 0)
fGenerate = false; fGenerate = false;
} }
GenerateBitcoins(fGenerate); GenerateBitcoins(fGenerate, pwalletMain);
return Value::null; return Value::null;
} }
@ -298,7 +298,7 @@ Value getinfo(const Array& params, bool fHelp)
Object obj; Object obj;
obj.push_back(Pair("version", (int)VERSION)); 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("blocks", (int)nBestHeight));
obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string()))); 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("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet)); 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("paytxfee", ValueFromAmount(nTransactionFee)));
obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj; return obj;
@ -329,9 +329,9 @@ Value getnewaddress(const Array& params, bool fHelp)
strAccount = AccountFromValue(params[0]); strAccount = AccountFromValue(params[0]);
// Generate a new key that is added to wallet // 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; return strAddress;
} }
@ -341,7 +341,7 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
{ {
string strAddress; string strAddress;
CWalletDB walletdb; CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin(); walletdb.TxnBegin();
CAccount account; CAccount account;
@ -352,8 +352,8 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
{ {
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey); scriptPubKey.SetBitcoinAddress(account.vchPubKey);
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != mapWallet.end() && !account.vchPubKey.empty(); it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it) ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
@ -366,9 +366,9 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
// Generate a new key // Generate a new key
if (account.vchPubKey.empty() || bForceNew) if (account.vchPubKey.empty() || bForceNew)
{ {
account.vchPubKey = GetKeyFromKeyPool(); account.vchPubKey = pwalletMain->GetKeyFromKeyPool();
string strAddress = PubKeyToAddress(account.vchPubKey); string strAddress = PubKeyToAddress(account.vchPubKey);
SetAddressBookName(strAddress, strAccount); pwalletMain->SetAddressBookName(strAddress, strAccount);
walletdb.WriteAccount(strAccount, account); walletdb.WriteAccount(strAccount, account);
} }
@ -391,7 +391,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
Value ret; Value ret;
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
ret = GetAccountAddress(strAccount); 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: // Detect when changing the account of an address that is the 'unused current key' of another account:
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(cs_mapAddressBook) 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)) if (strAddress == GetAccountAddress(strOldAccount))
GetAccountAddress(strOldAccount, true); GetAccountAddress(strOldAccount, true);
} }
} }
SetAddressBookName(strAddress, strAccount); pwalletMain->SetAddressBookName(strAddress, strAccount);
return Value::null; return Value::null;
} }
@ -447,10 +447,10 @@ Value getaccount(const Array& params, bool fHelp)
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
string strAccount; string strAccount;
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
map<string, string>::iterator mi = mapAddressBook.find(strAddress); map<string, string>::iterator mi = pwalletMain->mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end() && !(*mi).second.empty()) if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
strAccount = (*mi).second; strAccount = (*mi).second;
} }
return strAccount; return strAccount;
@ -468,9 +468,9 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
// Find all addresses that have the given account // Find all addresses that have the given account
Array ret; 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& strAddress = item.first;
const string& strName = item.second; const string& strName = item.second;
@ -523,7 +523,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
{ {
string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "") if (strError != "")
throw JSONRPCError(-4, strError); throw JSONRPCError(-4, strError);
} }
@ -544,7 +544,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
CScript scriptPubKey; CScript scriptPubKey;
if (!scriptPubKey.SetBitcoinAddress(strAddress)) if (!scriptPubKey.SetBitcoinAddress(strAddress))
throw JSONRPCError(-5, "Invalid bitcoin address"); throw JSONRPCError(-5, "Invalid bitcoin address");
if (!IsMine(scriptPubKey)) if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0; return (double)0.0;
// Minimum confirmations // Minimum confirmations
@ -554,9 +554,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
// Tally // Tally
int64 nAmount = 0; int64 nAmount = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal()) if (wtx.IsCoinBase() || !wtx.IsFinal())
@ -575,9 +575,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey) void GetAccountPubKeys(string strAccount, set<CScript>& 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& strAddress = item.first;
const string& strName = item.second; const string& strName = item.second;
@ -586,7 +586,7 @@ void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey)
// We're only counting our own valid bitcoin addresses and not ip addresses // We're only counting our own valid bitcoin addresses and not ip addresses
CScript scriptPubKey; CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress)) if (scriptPubKey.SetBitcoinAddress(strAddress))
if (IsMine(scriptPubKey)) if (IsMine(*pwalletMain,scriptPubKey))
setPubKey.insert(scriptPubKey); setPubKey.insert(scriptPubKey);
} }
} }
@ -613,9 +613,9 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
// Tally // Tally
int64 nAmount = 0; int64 nAmount = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal()) 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 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
{ {
int64 nBalance = 0; int64 nBalance = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
// Tally wallet transactions // Tally wallet transactions
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal()) if (!wtx.IsFinal())
@ -661,7 +661,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
int64 GetAccountBalance(const string& strAccount, int nMinDepth) int64 GetAccountBalance(const string& strAccount, int nMinDepth)
{ {
CWalletDB walletdb; CWalletDB walletdb(pwalletMain->strWalletFile);
return GetAccountBalance(walletdb, strAccount, nMinDepth); 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 [account] is specified, returns the balance in the account.");
if (params.size() == 0) if (params.size() == 0)
return ValueFromAmount(GetBalance()); return ValueFromAmount(pwalletMain->GetBalance());
int nMinDepth = 1; int nMinDepth = 1;
if (params.size() > 1) if (params.size() > 1)
@ -686,7 +686,7 @@ Value getbalance(const Array& params, bool fHelp)
// (GetBalance() sums up all unspent TxOuts) // (GetBalance() sums up all unspent TxOuts)
// getbalance and getbalance '*' should always return the same number. // getbalance and getbalance '*' should always return the same number.
int64 nBalance = 0; int64 nBalance = 0;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal()) if (!wtx.IsFinal())
@ -734,9 +734,9 @@ Value movecmd(const Array& params, bool fHelp)
if (params.size() > 4) if (params.size() > 4)
strComment = params[4].get_str(); strComment = params[4].get_str();
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
CWalletDB walletdb; CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin(); walletdb.TxnBegin();
int64 nNow = GetAdjustedTime(); int64 nNow = GetAdjustedTime();
@ -787,7 +787,7 @@ Value sendfrom(const Array& params, bool fHelp)
wtx.mapValue["to"] = params[5].get_str(); wtx.mapValue["to"] = params[5].get_str();
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
// Check funds // Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth); int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
@ -795,7 +795,7 @@ Value sendfrom(const Array& params, bool fHelp)
throw JSONRPCError(-6, "Account has insufficient funds"); throw JSONRPCError(-6, "Account has insufficient funds");
// Send // Send
string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "") if (strError != "")
throw JSONRPCError(-4, strError); throw JSONRPCError(-4, strError);
} }
@ -844,7 +844,7 @@ Value sendmany(const Array& params, bool fHelp)
} }
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
// Check funds // Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth); int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
@ -852,16 +852,16 @@ Value sendmany(const Array& params, bool fHelp)
throw JSONRPCError(-6, "Account has insufficient funds"); throw JSONRPCError(-6, "Account has insufficient funds");
// Send // Send
CReserveKey keyChange; CReserveKey keyChange(pwalletMain);
int64 nFeeRequired = 0; int64 nFeeRequired = 0;
bool fCreated = CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
if (!fCreated) if (!fCreated)
{ {
if (totalAmount + nFeeRequired > GetBalance()) if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
throw JSONRPCError(-6, "Insufficient funds"); throw JSONRPCError(-6, "Insufficient funds");
throw JSONRPCError(-4, "Transaction creation failed"); throw JSONRPCError(-4, "Transaction creation failed");
} }
if (!CommitTransaction(wtx, keyChange)) if (!pwalletMain->CommitTransaction(wtx, keyChange))
throw JSONRPCError(-4, "Transaction commit failed"); throw JSONRPCError(-4, "Transaction commit failed");
} }
@ -894,9 +894,9 @@ Value ListReceived(const Array& params, bool fByAccounts)
// Tally // Tally
map<uint160, tallyitem> mapTally; map<uint160, tallyitem> mapTally;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
if (wtx.IsCoinBase() || !wtx.IsFinal()) if (wtx.IsCoinBase() || !wtx.IsFinal())
@ -923,9 +923,9 @@ Value ListReceived(const Array& params, bool fByAccounts)
// Reply // Reply
Array ret; Array ret;
map<string, tallyitem> mapAccountTally; map<string, tallyitem> 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& strAddress = item.first;
const string& strAccount = item.second; const string& strAccount = item.second;
@ -1061,13 +1061,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Received // Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived) BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
{ {
string account; string account;
if (mapAddressBook.count(r.first)) if (pwalletMain->mapAddressBook.count(r.first))
account = mapAddressBook[r.first]; account = pwalletMain->mapAddressBook[r.first];
if (fAllAccounts || (account == strAccount)) if (fAllAccounts || (account == strAccount))
{ {
Object entry; Object entry;
@ -1119,16 +1119,16 @@ Value listtransactions(const Array& params, bool fHelp)
nFrom = params[2].get_int(); nFrom = params[2].get_int();
Array ret; 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: // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
typedef pair<CWalletTx*, CAccountingEntry*> TxPair; typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef multimap<int64, TxPair > TxItems; typedef multimap<int64, TxPair > TxItems;
TxItems txByTime; TxItems txByTime;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
CWalletTx* wtx = &((*it).second); CWalletTx* wtx = &((*it).second);
txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0))); 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(); nMinDepth = params[0].get_int();
map<string, int64> mapAccountBalances; map<string, int64> mapAccountBalances;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(string, string)& entry, mapAddressBook) { BOOST_FOREACH(const PAIRTYPE(string, string)& entry, pwalletMain->mapAddressBook) {
uint160 hash160; uint160 hash160;
if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me
mapAccountBalances[entry.second] = 0; mapAccountBalances[entry.second] = 0;
} }
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
int64 nGeneratedImmature, nGeneratedMature, nFee; int64 nGeneratedImmature, nGeneratedMature, nFee;
@ -1204,8 +1204,8 @@ Value listaccounts(const Array& params, bool fHelp)
{ {
mapAccountBalances[""] += nGeneratedMature; mapAccountBalances[""] += nGeneratedMature;
BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived) BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
if (mapAddressBook.count(r.first)) if (pwalletMain->mapAddressBook.count(r.first))
mapAccountBalances[mapAddressBook[r.first]] += r.second; mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
else else
mapAccountBalances[""] += r.second; mapAccountBalances[""] += r.second;
} }
@ -1213,7 +1213,7 @@ Value listaccounts(const Array& params, bool fHelp)
} }
list<CAccountingEntry> acentries; list<CAccountingEntry> acentries;
CWalletDB().ListAccountCreditDebit("*", acentries); CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
BOOST_FOREACH(const CAccountingEntry& entry, acentries) BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit; mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
@ -1235,11 +1235,11 @@ Value gettransaction(const Array& params, bool fHelp)
hash.SetHex(params[0].get_str()); hash.SetHex(params[0].get_str());
Object entry; 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"); 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 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit(); int64 nDebit = wtx.GetDebit();
@ -1250,10 +1250,10 @@ Value gettransaction(const Array& params, bool fHelp)
if (wtx.IsFromMe()) if (wtx.IsFromMe())
entry.push_back(Pair("fee", ValueFromAmount(nFee))); entry.push_back(Pair("fee", ValueFromAmount(nFee)));
WalletTxToJSON(mapWallet[hash], entry); WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
Array details; Array details;
ListTransactions(mapWallet[hash], "*", 0, false, details); ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
entry.push_back(Pair("details", 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."); "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
string strDest = params[0].get_str(); string strDest = params[0].get_str();
BackupWallet(strDest); BackupWallet(*pwalletMain, strDest);
return Value::null; return Value::null;
} }
@ -1295,10 +1295,10 @@ Value validateaddress(const Array& params, bool fHelp)
string currentAddress = Hash160ToAddress(hash160); string currentAddress = Hash160ToAddress(hash160);
ret.push_back(Pair("address", currentAddress)); ret.push_back(Pair("address", currentAddress));
ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0))); ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0)));
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
if (mapAddressBook.count(currentAddress)) if (pwalletMain->mapAddressBook.count(currentAddress))
ret.push_back(Pair("account", mapAddressBook[currentAddress])); ret.push_back(Pair("account", pwalletMain->mapAddressBook[currentAddress]));
} }
} }
return ret; return ret;
@ -1325,7 +1325,7 @@ Value getwork(const Array& params, bool fHelp)
static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock; static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
static vector<CBlock*> vNewBlock; static vector<CBlock*> vNewBlock;
static CReserveKey reservekey; static CReserveKey reservekey(pwalletMain);
if (params.size() == 0) 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->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->hashMerkleRoot = pblock->BuildMerkleTree();
return CheckWork(pblock, reservekey); return CheckWork(pblock, *pwalletMain, reservekey);
} }
} }

View file

@ -1021,7 +1021,7 @@ bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& 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(); scriptSigRet.clear();
@ -1030,7 +1030,7 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s
return false; return false;
// Compile solution // Compile solution
CRITICAL_BLOCK(cs_mapKeys) CRITICAL_BLOCK(keystore.cs_mapKeys)
{ {
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{ {
@ -1038,12 +1038,12 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s
{ {
// Sign // Sign
const valtype& vchPubKey = item.second; const valtype& vchPubKey = item.second;
if (!mapKeys.count(vchPubKey)) if (!keystore.HaveKey(vchPubKey))
return false; return false;
if (hash != 0) if (hash != 0)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig)) if (!CKey::Sign(keystore.GetPrivKey(vchPubKey), hash, vchSig))
return false; return false;
vchSig.push_back((unsigned char)nHashType); vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig; scriptSigRet << vchSig;
@ -1056,12 +1056,12 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s
if (mi == mapPubKeys.end()) if (mi == mapPubKeys.end())
return false; return false;
const vector<unsigned char>& vchPubKey = (*mi).second; const vector<unsigned char>& vchPubKey = (*mi).second;
if (!mapKeys.count(vchPubKey)) if (!keystore.HaveKey(vchPubKey))
return false; return false;
if (hash != 0) if (hash != 0)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig)) if (!CKey::Sign(keystore.GetPrivKey(vchPubKey), hash, vchSig))
return false; return false;
vchSig.push_back((unsigned char)nHashType); vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << vchPubKey; 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; CScript scriptSig;
return Solver(scriptPubKey, 0, 0, scriptSig); return Solver(keystore, scriptPubKey, 0, 0, scriptSig);
} }
bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned char>& vchPubKeyRet) bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* keystore, vector<unsigned char>& vchPubKeyRet)
{ {
vchPubKeyRet.clear(); vchPubKeyRet.clear();
@ -1100,7 +1100,7 @@ bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned
if (!Solver(scriptPubKey, vSolution)) if (!Solver(scriptPubKey, vSolution))
return false; return false;
CRITICAL_BLOCK(cs_mapKeys) CRITICAL_BLOCK(cs_mapPubKeys)
{ {
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{ {
@ -1116,7 +1116,7 @@ bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned
continue; continue;
vchPubKey = (*mi).second; vchPubKey = (*mi).second;
} }
if (!fMineOnly || mapKeys.count(vchPubKey)) if (keystore == NULL || keystore->HaveKey(vchPubKey))
{ {
vchPubKeyRet = vchPubKey; vchPubKeyRet = vchPubKey;
return true; 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()); assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn]; 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. // The checksig op will also drop the signatures from its hash.
uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType); 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; return false;
txin.scriptSig = scriptPrereq + txin.scriptSig; 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)) if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType))
return false; 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; return true;
} }

View file

@ -708,12 +708,11 @@ public:
uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
bool IsStandard(const CScript& scriptPubKey); bool IsStandard(const CScript& scriptPubKey);
bool IsMine(const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, std::vector<unsigned char>& vchPubKeyRet); bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* pkeystore, std::vector<unsigned char>& vchPubKeyRet);
bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret); 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); bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0);
#endif #endif

View file

@ -240,7 +240,7 @@ void SetDefaultReceivingAddress(const string& strAddress)
return; return;
if (!mapPubKeys.count(hash160)) if (!mapPubKeys.count(hash160))
return; return;
CWalletDB().WriteDefaultKey(mapPubKeys[hash160]); CWalletDB(pwalletMain->strWalletFile).WriteDefaultKey(mapPubKeys[hash160]);
pframeMain->m_textCtrlAddress->SetValue(strAddress); pframeMain->m_textCtrlAddress->SetValue(strAddress);
} }
} }
@ -290,7 +290,7 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
dResize = 1.22; dResize = 1.22;
SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight()); SetSize(dResize * GetSize().GetWidth(), 1.15 * GetSize().GetHeight());
#endif #endif
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
m_listCtrl->SetFocus(); m_listCtrl->SetFocus();
ptaskbaricon = new CMyTaskBarIcon(); ptaskbaricon = new CMyTaskBarIcon();
#ifdef __WXMAC_OSX__ #ifdef __WXMAC_OSX__
@ -330,7 +330,7 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent)
// Fill your address text box // Fill your address text box
vector<unsigned char> vchPubKey; vector<unsigned char> vchPubKey;
if (CWalletDB("r").ReadDefaultKey(vchPubKey)) if (CWalletDB(pwalletMain->strWalletFile,"r").ReadDefaultKey(vchPubKey))
m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey)); m_textCtrlAddress->SetValue(PubKeyToAddress(vchPubKey));
// Fill listctrl with wallet transactions // Fill listctrl with wallet transactions
@ -625,7 +625,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
{ {
int64 nUnmatured = 0; int64 nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit(); nUnmatured += pwalletMain->GetCredit(txout);
if (wtx.IsInMainChain()) if (wtx.IsInMainChain())
{ {
strDescription = strprintf(_("Generated (%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); 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; return false;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
if (txout.IsMine()) if (pwalletMain->IsMine(txout))
{ {
vector<unsigned char> vchPubKey; vector<unsigned char> 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 payment to ");
//strDescription += _("Received with address "); //strDescription += _("Received with address ");
strDescription += _("Received with: "); strDescription += _("Received with: ");
string strAddress = PubKeyToAddress(vchPubKey); string strAddress = PubKeyToAddress(vchPubKey);
map<string, string>::iterator mi = mapAddressBook.find(strAddress); map<string, string>::iterator mi = pwalletMain->mapAddressBook.find(strAddress);
if (mi != mapAddressBook.end() && !(*mi).second.empty()) if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
{ {
string strLabel = (*mi).second; string strLabel = (*mi).second;
strDescription += strAddress.substr(0,12) + "... "; strDescription += strAddress.substr(0,12) + "... ";
@ -703,11 +703,11 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
{ {
bool fAllFromMe = true; bool fAllFromMe = true;
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && txin.IsMine(); fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
bool fAllToMe = true; bool fAllToMe = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && txout.IsMine(); fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
if (fAllFromMe && fAllToMe) 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++) for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
{ {
const CTxOut& txout = wtx.vout[nOut]; const CTxOut& txout = wtx.vout[nOut];
if (txout.IsMine()) if (pwalletMain->IsMine(txout))
continue; continue;
string strAddress; string strAddress;
@ -751,9 +751,9 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
} }
string strDescription = _("To: "); string strDescription = _("To: ");
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
strDescription += mapAddressBook[strAddress] + " "; strDescription += pwalletMain->mapAddressBook[strAddress] + " ";
strDescription += strAddress; strDescription += strAddress;
if (!mapValue["message"].empty()) if (!mapValue["message"].empty())
{ {
@ -792,9 +792,9 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
// //
bool fAllMine = true; bool fAllMine = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
fAllMine = fAllMine && txout.IsMine(); fAllMine = fAllMine && pwalletMain->IsMine(txout);
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
fAllMine = fAllMine && txin.IsMine(); fAllMine = fAllMine && pwalletMain->IsMine(txin);
InsertLine(fNew, nIndex, hash, strSort, colour, InsertLine(fNew, nIndex, hash, strSort, colour,
strStatus, strStatus,
@ -821,16 +821,16 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
// Collect list of wallet transactions and sort newest first // Collect list of wallet transactions and sort newest first
bool fEntered = false; bool fEntered = false;
vector<pair<unsigned int, uint256> > vSorted; vector<pair<unsigned int, uint256> > vSorted;
TRY_CRITICAL_BLOCK(cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
printf("RefreshListCtrl starting\n"); printf("RefreshListCtrl starting\n");
fEntered = true; fEntered = true;
fRefreshListCtrl = false; fRefreshListCtrl = false;
vWalletUpdated.clear(); pwalletMain->vWalletUpdated.clear();
// Do the newest transactions first // Do the newest transactions first
vSorted.reserve(mapWallet.size()); vSorted.reserve(pwalletMain->mapWallet.size());
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
const CWalletTx& wtx = (*it).second; const CWalletTx& wtx = (*it).second;
unsigned int nTime = UINT_MAX - wtx.GetTxTime(); unsigned int nTime = UINT_MAX - wtx.GetTxTime();
@ -849,12 +849,12 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
if (fShutdown) if (fShutdown)
return; return;
bool fEntered = false; bool fEntered = false;
TRY_CRITICAL_BLOCK(cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
fEntered = true; fEntered = true;
uint256& hash = vSorted[i++].second; uint256& hash = vSorted[i++].second;
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash); map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
if (mi != mapWallet.end()) if (mi != pwalletMain->mapWallet.end())
InsertTransaction((*mi).second, true); InsertTransaction((*mi).second, true);
} }
if (!fEntered || i == 100 || i % 500 == 0) if (!fEntered || i == 100 || i % 500 == 0)
@ -872,10 +872,10 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
static int64 nLastTime; static int64 nLastTime;
if (GetTime() > nLastTime + 30) if (GetTime() > nLastTime + 30)
{ {
TRY_CRITICAL_BLOCK(cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
nLastTime = GetTime(); nLastTime = GetTime();
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
CWalletTx& wtx = (*it).second; CWalletTx& wtx = (*it).second;
if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime()) if (wtx.nTimeDisplayed && wtx.nTimeDisplayed != wtx.GetTxTime())
@ -896,7 +896,7 @@ void CMainFrame::RefreshStatusColumn()
if (nTop == nLastTop && pindexLastBest == pindexBest) if (nTop == nLastTop && pindexLastBest == pindexBest)
return; return;
TRY_CRITICAL_BLOCK(cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
int nStart = nTop; int nStart = nTop;
int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); 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++) for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
{ {
uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash); map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
if (mi == mapWallet.end()) if (mi == pwalletMain->mapWallet.end())
{ {
printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n"); printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
continue; continue;
@ -1014,41 +1014,41 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
nLastRepaintTime = GetTimeMillis(); nLastRepaintTime = GetTimeMillis();
// Update listctrl contents // Update listctrl contents
if (!vWalletUpdated.empty()) if (!pwalletMain->vWalletUpdated.empty())
{ {
TRY_CRITICAL_BLOCK(cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
string strTop; string strTop;
if (m_listCtrl->GetItemCount()) if (m_listCtrl->GetItemCount())
strTop = (string)m_listCtrl->GetItemText(0); strTop = (string)m_listCtrl->GetItemText(0);
BOOST_FOREACH(uint256 hash, vWalletUpdated) BOOST_FOREACH(uint256 hash, pwalletMain->vWalletUpdated)
{ {
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash); map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
if (mi != mapWallet.end()) if (mi != pwalletMain->mapWallet.end())
InsertTransaction((*mi).second, false); InsertTransaction((*mi).second, false);
} }
vWalletUpdated.clear(); pwalletMain->vWalletUpdated.clear();
if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0)) if (m_listCtrl->GetItemCount() && strTop != (string)m_listCtrl->GetItemText(0))
m_listCtrl->ScrollList(0, INT_MIN/2); m_listCtrl->ScrollList(0, INT_MIN/2);
} }
} }
// Balance total // Balance total
TRY_CRITICAL_BLOCK(cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
fPaintedBalance = true; fPaintedBalance = true;
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
// Count hidden and multi-line transactions // Count hidden and multi-line transactions
nTransactionCount = 0; nTransactionCount = 0;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
CWalletTx& wtx = (*it).second; CWalletTx& wtx = (*it).second;
nTransactionCount += wtx.nLinesDisplayed; nTransactionCount += wtx.nLinesDisplayed;
} }
} }
} }
if (!vWalletUpdated.empty() || !fPaintedBalance) if (!pwalletMain->vWalletUpdated.empty() || !fPaintedBalance)
nNeedRepaint++; nNeedRepaint++;
// Update status column of visible items only // Update status column of visible items only
@ -1074,7 +1074,7 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
m_statusBar->SetStatusText(strStatus, 2); m_statusBar->SetStatusText(strStatus, 2);
// Update receiving address // Update receiving address
string strDefaultAddress = PubKeyToAddress(vchDefaultKey); string strDefaultAddress = PubKeyToAddress(pwalletMain->vchDefaultKey);
if (m_textCtrlAddress->GetValue() != strDefaultAddress) if (m_textCtrlAddress->GetValue() != strDefaultAddress)
m_textCtrlAddress->SetValue(strDefaultAddress); m_textCtrlAddress->SetValue(strDefaultAddress);
} }
@ -1183,10 +1183,10 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
string strName = dialog.GetValue(); string strName = dialog.GetValue();
// Generate new key // Generate new key
string strAddress = PubKeyToAddress(GetKeyFromKeyPool()); string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
// Save // Save
SetAddressBookName(strAddress, strName); pwalletMain->SetAddressBookName(strAddress, strName);
SetDefaultReceivingAddress(strAddress); SetDefaultReceivingAddress(strAddress);
} }
@ -1204,10 +1204,10 @@ void CMainFrame::OnListItemActivated(wxListEvent& event)
{ {
uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1)); uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
CWalletTx wtx; CWalletTx wtx;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash); map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
if (mi == mapWallet.end()) if (mi == pwalletMain->mapWallet.end())
{ {
printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n"); printf("CMainFrame::OnListItemActivated() : tx not found in mapWallet\n");
return; return;
@ -1235,7 +1235,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
#ifdef __WXMSW__ #ifdef __WXMSW__
SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight()); SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
#endif #endif
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
string strHTML; string strHTML;
strHTML.reserve(4000); strHTML.reserve(4000);
@ -1285,19 +1285,19 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
// Credit // Credit
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
if (txout.IsMine()) if (pwalletMain->IsMine(txout))
{ {
vector<unsigned char> vchPubKey; vector<unsigned char> vchPubKey;
if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey)) if (ExtractPubKey(txout.scriptPubKey, pwalletMain, vchPubKey))
{ {
string strAddress = PubKeyToAddress(vchPubKey); string strAddress = PubKeyToAddress(vchPubKey);
if (mapAddressBook.count(strAddress)) if (pwalletMain->mapAddressBook.count(strAddress))
{ {
strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>"; strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
strHTML += _("<b>To:</b> "); strHTML += _("<b>To:</b> ");
strHTML += HtmlEscape(strAddress); strHTML += HtmlEscape(strAddress);
if (!mapAddressBook[strAddress].empty()) if (!pwalletMain->mapAddressBook[strAddress].empty())
strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")"; strHTML += _(" (yours, label: ") + pwalletMain->mapAddressBook[strAddress] + ")";
else else
strHTML += _(" (yours)"); strHTML += _(" (yours)");
strHTML += "<br>"; strHTML += "<br>";
@ -1319,8 +1319,8 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
// Online transaction // Online transaction
strAddress = wtx.mapValue["to"]; strAddress = wtx.mapValue["to"];
strHTML += _("<b>To:</b> "); strHTML += _("<b>To:</b> ");
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " "; strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
strHTML += HtmlEscape(strAddress) + "<br>"; strHTML += HtmlEscape(strAddress) + "<br>";
} }
@ -1335,7 +1335,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
// //
int64 nUnmatured = 0; int64 nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
nUnmatured += txout.GetCredit(); nUnmatured += pwalletMain->GetCredit(txout);
strHTML += _("<b>Credit:</b> "); strHTML += _("<b>Credit:</b> ");
if (wtx.IsInMainChain()) if (wtx.IsInMainChain())
strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity()); 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; bool fAllFromMe = true;
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
fAllFromMe = fAllFromMe && txin.IsMine(); fAllFromMe = fAllFromMe && pwalletMain->IsMine(txin);
bool fAllToMe = true; bool fAllToMe = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
fAllToMe = fAllToMe && txout.IsMine(); fAllToMe = fAllToMe && pwalletMain->IsMine(txout);
if (fAllFromMe) if (fAllFromMe)
{ {
@ -1367,7 +1367,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
// //
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
if (txout.IsMine()) if (pwalletMain->IsMine(txout))
continue; continue;
if (wtx.mapValue["to"].empty()) if (wtx.mapValue["to"].empty())
@ -1378,8 +1378,8 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
{ {
string strAddress = Hash160ToAddress(hash160); string strAddress = Hash160ToAddress(hash160);
strHTML += _("<b>To:</b> "); strHTML += _("<b>To:</b> ");
if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty()) if (pwalletMain->mapAddressBook.count(strAddress) && !pwalletMain->mapAddressBook[strAddress].empty())
strHTML += mapAddressBook[strAddress] + " "; strHTML += pwalletMain->mapAddressBook[strAddress] + " ";
strHTML += strAddress; strHTML += strAddress;
strHTML += "<br>"; strHTML += "<br>";
} }
@ -1407,11 +1407,11 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
// Mixed debit transaction // Mixed debit transaction
// //
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
if (txin.IsMine()) if (pwalletMain->IsMine(txin))
strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>"; strHTML += _("<b>Debit:</b> ") + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.IsMine()) if (pwalletMain->IsMine(txout))
strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>"; strHTML += _("<b>Credit:</b> ") + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
} }
} }
@ -1437,30 +1437,30 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
{ {
strHTML += "<hr><br>debug print<br><br>"; strHTML += "<hr><br>debug print<br><br>";
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
if (txin.IsMine()) if (pwalletMain->IsMine(txin))
strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>"; strHTML += "<b>Debit:</b> " + FormatMoney(-pwalletMain->GetDebit(txin)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.IsMine()) if (pwalletMain->IsMine(txout))
strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>"; strHTML += "<b>Credit:</b> " + FormatMoney(pwalletMain->GetCredit(txout)) + "<br>";
strHTML += "<br><b>Transaction:</b><br>"; strHTML += "<br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true); strHTML += HtmlEscape(wtx.ToString(), true);
strHTML += "<br><b>Inputs:</b><br>"; strHTML += "<br><b>Inputs:</b><br>";
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{ {
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{ {
COutPoint prevout = txin.prevout; COutPoint prevout = txin.prevout;
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash); map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(prevout.hash);
if (mi != mapWallet.end()) if (mi != pwalletMain->mapWallet.end())
{ {
const CWalletTx& prev = (*mi).second; const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size()) if (prevout.n < prev.vout.size())
{ {
strHTML += HtmlEscape(prev.ToString(), true); strHTML += HtmlEscape(prev.ToString(), true);
strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", "; strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>"; strHTML = strHTML + "IsMine=" + (pwalletMain->IsMine(prev.vout[prevout.n]) ? "true" : "false") + "<br>";
} }
} }
} }
@ -1751,7 +1751,7 @@ void COptionsDialog::OnButtonCancel(wxCommandEvent& event)
void COptionsDialog::OnButtonApply(wxCommandEvent& event) void COptionsDialog::OnButtonApply(wxCommandEvent& event)
{ {
CWalletDB walletdb; CWalletDB walletdb(pwalletMain->strWalletFile);
int64 nPrevTransactionFee = nTransactionFee; int64 nPrevTransactionFee = nTransactionFee;
if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee) if (ParseMoney(m_textCtrlTransactionFee->GetValue(), nTransactionFee) && nTransactionFee != nPrevTransactionFee)
@ -1928,12 +1928,12 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
wxMessageBox(_("Error in amount "), _("Send Coins")); wxMessageBox(_("Error in amount "), _("Send Coins"));
return; return;
} }
if (nValue > GetBalance()) if (nValue > pwalletMain->GetBalance())
{ {
wxMessageBox(_("Amount exceeds your balance "), _("Send Coins")); wxMessageBox(_("Amount exceeds your balance "), _("Send Coins"));
return; 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")); wxMessageBox(string(_("Total exceeds your balance when the ")) + FormatMoney(nTransactionFee) + _(" transaction fee is included "), _("Send Coins"));
return; return;
@ -1951,7 +1951,7 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; 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 == "") if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending...")); wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError == "ABORTED") else if (strError == "ABORTED")
@ -1983,9 +1983,9 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
return; return;
} }
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
if (!mapAddressBook.count(strAddress)) if (!pwalletMain->mapAddressBook.count(strAddress))
SetAddressBookName(strAddress, ""); pwalletMain->SetAddressBookName(strAddress, "");
EndModal(true); EndModal(true);
} }
@ -2169,7 +2169,7 @@ void SendingDialogStartTransfer(void* parg)
void CSendingDialog::StartTransfer() void CSendingDialog::StartTransfer()
{ {
// Make sure we have enough money // Make sure we have enough money
if (nPrice + nTransactionFee > GetBalance()) if (nPrice + nTransactionFee > pwalletMain->GetBalance())
{ {
Error(_("Insufficient funds")); Error(_("Insufficient funds"));
return; return;
@ -2240,16 +2240,16 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
// Pay // Pay
if (!Status(_("Creating transaction..."))) if (!Status(_("Creating transaction...")))
return; return;
if (nPrice + nTransactionFee > GetBalance()) if (nPrice + nTransactionFee > pwalletMain->GetBalance())
{ {
Error(_("Insufficient funds")); Error(_("Insufficient funds"));
return; return;
} }
CReserveKey reservekey; CReserveKey reservekey(pwalletMain);
int64 nFeeRequired; 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())); 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 else
Error(_("Transaction creation failed")); Error(_("Transaction creation failed"));
@ -2287,7 +2287,7 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
return; return;
// Commit // 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.")); 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; return;
@ -2381,11 +2381,11 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus(); m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data // Fill listctrl with address book data
CRITICAL_BLOCK(cs_mapKeys) CRITICAL_BLOCK(pwalletMain->cs_mapKeys)
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue(); 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 strAddress = item.first;
string strName = item.second; string strName = item.second;
@ -2444,7 +2444,7 @@ void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
if (event.IsEditCancelled()) if (event.IsEditCancelled())
return; return;
string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
SetAddressBookName(strAddress, string(event.GetText())); pwalletMain->SetAddressBookName(strAddress, string(event.GetText()));
pframeMain->RefreshListCtrl(); pframeMain->RefreshListCtrl();
} }
@ -2479,7 +2479,7 @@ void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED)) if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
{ {
string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
CWalletDB().EraseName(strAddress); CWalletDB(pwalletMain->strWalletFile).EraseName(strAddress);
m_listCtrl->DeleteItem(nIndex); m_listCtrl->DeleteItem(nIndex);
} }
} }
@ -2539,8 +2539,8 @@ void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
// Write back // Write back
if (strAddress != strAddressOrg) if (strAddress != strAddressOrg)
CWalletDB().EraseName(strAddressOrg); CWalletDB(pwalletMain->strWalletFile).EraseName(strAddressOrg);
SetAddressBookName(strAddress, strName); pwalletMain->SetAddressBookName(strAddress, strName);
m_listCtrl->SetItem(nIndex, 1, strAddress); m_listCtrl->SetItem(nIndex, 1, strAddress);
m_listCtrl->SetItemText(nIndex, strName); m_listCtrl->SetItemText(nIndex, strName);
pframeMain->RefreshListCtrl(); pframeMain->RefreshListCtrl();
@ -2576,11 +2576,11 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
strName = dialog.GetValue(); strName = dialog.GetValue();
// Generate new key // Generate new key
strAddress = PubKeyToAddress(GetKeyFromKeyPool()); strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
} }
// Add to list and select it // Add to list and select it
SetAddressBookName(strAddress, strName); pwalletMain->SetAddressBookName(strAddress, strName);
int nIndex = InsertLine(m_listCtrl, strName, strAddress); int nIndex = InsertLine(m_listCtrl, strName, strAddress);
SetSelection(m_listCtrl, nIndex); SetSelection(m_listCtrl, nIndex);
m_listCtrl->SetFocus(); m_listCtrl->SetFocus();

View file

@ -15,29 +15,40 @@ using namespace std;
// mapWallet // 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. // 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 // 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. // restored from backup or the user making copies of wallet.dat.
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash); BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (mi != mapWallet.end())
{ {
CWalletTx& wtx = (*mi).second; map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine()) if (mi != mapWallet.end())
{ {
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); CWalletTx& wtx = (*mi).second;
wtx.MarkSpent(prevout.n); if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
wtx.WriteToDisk(); {
vWalletUpdated.push_back(prevout.hash); 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(); uint256 hash = wtxIn.GetHash();
CRITICAL_BLOCK(cs_mapWallet) 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 // Inserts only if not already there, returns tx inserted or tx found
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second; CWalletTx& wtx = (*ret.first).second;
wtx.pwallet = this;
bool fInsertedNew = ret.second; bool fInsertedNew = ret.second;
if (fInsertedNew) if (fInsertedNew)
wtx.nTimeReceived = GetAdjustedTime(); wtx.nTimeReceived = GetAdjustedTime();
@ -87,7 +99,9 @@ bool AddToWallet(const CWalletTx& wtxIn)
{ {
if (txout.scriptPubKey == scriptDefaultKey) if (txout.scriptPubKey == scriptDefaultKey)
{ {
CWalletDB walletdb; if (!fFileBacked)
continue;
CWalletDB walletdb(strWalletFile);
vchDefaultKey = GetKeyFromKeyPool(); vchDefaultKey = GetKeyFromKeyPool();
walletdb.WriteDefaultKey(vchDefaultKey); walletdb.WriteDefaultKey(vchDefaultKey);
walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
@ -96,6 +110,9 @@ bool AddToWallet(const CWalletTx& wtxIn)
// Notify UI // Notify UI
vWalletUpdated.push_back(hash); vWalletUpdated.push_back(hash);
// since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
WalletUpdateSpent(wtx);
} }
// Refresh UI // Refresh UI
@ -103,60 +120,64 @@ bool AddToWallet(const CWalletTx& wtxIn)
return true; 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(); uint256 hash = tx.GetHash();
bool fExisted = mapWallet.count(hash); bool fExisted = mapWallet.count(hash);
if (fExisted && !fUpdate) return false; 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 // Get merkle branch if transaction was found in a block
if (pblock) if (pblock)
wtx.SetMerkleBranch(pblock); wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx); return AddToWallet(wtx);
} }
else
WalletUpdateSpent(tx);
return false; return false;
} }
bool EraseFromWallet(uint256 hash) bool CWallet::EraseFromWallet(uint256 hash)
{ {
if (!fFileBacked)
return false;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
if (mapWallet.erase(hash)) if (mapWallet.erase(hash))
CWalletDB().EraseTx(hash); CWalletDB(strWalletFile).EraseTx(hash);
} }
return true; return true;
} }
bool CTxIn::IsMine() const bool CWallet::IsMine(const CTxIn &txin) const
{ {
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash); map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end()) if (mi != mapWallet.end())
{ {
const CWalletTx& prev = (*mi).second; const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size()) if (txin.prevout.n < prev.vout.size())
if (prev.vout[prevout.n].IsMine()) if (IsMine(prev.vout[txin.prevout.n]))
return true; return true;
} }
} }
return false; return false;
} }
int64 CTxIn::GetDebit() const int64 CWallet::GetDebit(const CTxIn &txin) const
{ {
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash); map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end()) if (mi != mapWallet.end())
{ {
const CWalletTx& prev = (*mi).second; const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size()) if (txin.prevout.n < prev.vout.size())
if (prev.vout[prevout.n].IsMine()) if (IsMine(prev.vout[txin.prevout.n]))
return prev.vout[prevout.n].nValue; return prev.vout[txin.prevout.n].nValue;
} }
} }
return 0; return 0;
@ -184,31 +205,31 @@ int CWalletTx::GetRequestCount() const
{ {
// Returns -1 if it wasn't being tracked // Returns -1 if it wasn't being tracked
int nRequests = -1; int nRequests = -1;
CRITICAL_BLOCK(cs_mapRequestCount) CRITICAL_BLOCK(pwallet->cs_mapRequestCount)
{ {
if (IsCoinBase()) if (IsCoinBase())
{ {
// Generated block // Generated block
if (hashBlock != 0) if (hashBlock != 0)
{ {
map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock); map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != mapRequestCount.end()) if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second; nRequests = (*mi).second;
} }
} }
else else
{ {
// Did anyone request this transaction? // Did anyone request this transaction?
map<uint256, int>::iterator mi = mapRequestCount.find(GetHash()); map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
if (mi != mapRequestCount.end()) if (mi != pwallet->mapRequestCount.end())
{ {
nRequests = (*mi).second; nRequests = (*mi).second;
// How about the block it's in? // How about the block it's in?
if (nRequests == 0 && hashBlock != 0) if (nRequests == 0 && hashBlock != 0)
{ {
map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock); map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != mapRequestCount.end()) if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second; nRequests = (*mi).second;
else else
nRequests = 1; // If it's in someone else's block it must have got out 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 (IsCoinBase())
{ {
if (GetBlocksToMaturity() > 0) if (GetBlocksToMaturity() > 0)
nGeneratedImmature = CTransaction::GetCredit(); nGeneratedImmature = pwallet->GetCredit(*this);
else else
nGeneratedMature = GetCredit(); nGeneratedMature = GetCredit();
return; return;
@ -263,13 +284,13 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l
} }
// Don't report 'change' txouts // Don't report 'change' txouts
if (nDebit > 0 && txout.IsChange()) if (nDebit > 0 && pwallet->IsChange(txout))
continue; continue;
if (nDebit > 0) if (nDebit > 0)
listSent.push_back(make_pair(address, txout.nValue)); listSent.push_back(make_pair(address, txout.nValue));
if (txout.IsMine()) if (pwallet->IsMine(txout))
listReceived.push_back(make_pair(address, txout.nValue)); listReceived.push_back(make_pair(address, txout.nValue));
} }
@ -295,16 +316,15 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i
nSent += s.second; nSent += s.second;
nFee = allFee; nFee = allFee;
} }
CRITICAL_BLOCK(cs_mapAddressBook) CRITICAL_BLOCK(pwallet->cs_mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived) 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<string, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
{ if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
nReceived += r.second; nReceived += r.second;
}
} }
else if (strAccount.empty()) else if (strAccount.empty())
{ {
@ -326,7 +346,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
vWorkQueue.push_back(txin.prevout.hash); vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open // This critsect is OK because txdb is already open
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(pwallet->cs_mapWallet)
{ {
map<uint256, const CMerkleTx*> mapWalletPrev; map<uint256, const CMerkleTx*> mapWalletPrev;
set<uint256> setAlreadyDone; set<uint256> setAlreadyDone;
@ -338,10 +358,11 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
setAlreadyDone.insert(hash); setAlreadyDone.insert(hash);
CMerkleTx tx; CMerkleTx tx;
if (mapWallet.count(hash)) map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
if (mi != pwallet->mapWallet.end())
{ {
tx = mapWallet[hash]; tx = (*mi).second;
BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev) BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev; mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
} }
else if (mapWalletPrev.count(hash)) else if (mapWalletPrev.count(hash))
@ -373,10 +394,10 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
bool CWalletTx::WriteToDisk() 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; int ret = 0;
@ -398,7 +419,7 @@ int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
return ret; return ret;
} }
void ReacceptWalletTransactions() void CWallet::ReacceptWalletTransactions()
{ {
CTxDB txdb("r"); CTxDB txdb("r");
bool fRepeat = true; bool fRepeat = true;
@ -426,7 +447,7 @@ void ReacceptWalletTransactions()
{ {
if (wtx.IsSpent(i)) if (wtx.IsSpent(i))
continue; continue;
if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine()) if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
{ {
wtx.MarkSpent(i); wtx.MarkSpent(i);
fUpdated = true; fUpdated = true;
@ -484,7 +505,7 @@ void CWalletTx::RelayWalletTransaction()
RelayWalletTransaction(txdb); RelayWalletTransaction(txdb);
} }
void ResendWalletTransactions() void CWallet::ResendWalletTransactions()
{ {
// Do this infrequently and randomly to avoid giving away // Do this infrequently and randomly to avoid giving away
// that these are our transactions. // that these are our transactions.
@ -536,16 +557,16 @@ void ResendWalletTransactions()
// //
int64 GetBalance() int64 CWallet::GetBalance() const
{ {
int64 nStart = GetTimeMillis(); int64 nStart = GetTimeMillis();
int64 nTotal = 0; int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{ {
CWalletTx* pcoin = &(*it).second; const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
continue; continue;
nTotal += pcoin->GetAvailableCredit(); nTotal += pcoin->GetAvailableCredit();
@ -557,27 +578,27 @@ int64 GetBalance()
} }
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
{ {
setCoinsRet.clear(); setCoinsRet.clear();
nValueRet = 0; nValueRet = 0;
// List of values less than target // List of values less than target
pair<int64, pair<CWalletTx*,unsigned int> > coinLowestLarger; pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
coinLowestLarger.first = INT64_MAX; coinLowestLarger.first = INT64_MAX;
coinLowestLarger.second.first = NULL; coinLowestLarger.second.first = NULL;
vector<pair<int64, pair<CWalletTx*,unsigned int> > > vValue; vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
int64 nTotalLower = 0; int64 nTotalLower = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
vector<CWalletTx*> vCoins; vector<const CWalletTx*> vCoins;
vCoins.reserve(mapWallet.size()); vCoins.reserve(mapWallet.size());
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
vCoins.push_back(&(*it).second); vCoins.push_back(&(*it).second);
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
BOOST_FOREACH(CWalletTx* pcoin, vCoins) BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
{ {
if (!pcoin->IsFinal() || !pcoin->IsConfirmed()) if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
continue; continue;
@ -591,7 +612,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
for (int i = 0; i < pcoin->vout.size(); i++) 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; continue;
int64 n = pcoin->vout[i].nValue; int64 n = pcoin->vout[i].nValue;
@ -599,7 +620,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
if (n <= 0) if (n <= 0)
continue; continue;
pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i)); pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
if (n == nTargetValue) if (n == nTargetValue)
{ {
@ -702,7 +723,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
return true; return true;
} }
bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
{ {
return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) || return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
@ -712,7 +733,7 @@ bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoi
bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
{ {
int64 nValue = 0; int64 nValue = 0;
BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
@ -724,6 +745,8 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
if (vecSend.empty() || nValue < 0) if (vecSend.empty() || nValue < 0)
return false; return false;
wtxNew.pwallet = this;
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
{ {
// txdb must be opened before the mapWallet lock // txdb must be opened before the mapWallet lock
@ -744,11 +767,11 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
wtxNew.vout.push_back(CTxOut(s.second, s.first)); wtxNew.vout.push_back(CTxOut(s.second, s.first));
// Choose coins to use // Choose coins to use
set<pair<CWalletTx*,unsigned int> > setCoins; set<pair<const CWalletTx*,unsigned int> > setCoins;
int64 nValueIn = 0; int64 nValueIn = 0;
if (!SelectCoins(nTotalValue, setCoins, nValueIn)) if (!SelectCoins(nTotalValue, setCoins, nValueIn))
return false; 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; int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
@ -784,13 +807,13 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
reservekey.ReturnKey(); reservekey.ReturnKey();
// Fill vin // 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)); wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign // Sign
int nIn = 0; int nIn = 0;
BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins) BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
if (!SignSignature(*coin.first, wtxNew, nIn++)) if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
return false; return false;
// Limit size // Limit size
@ -820,7 +843,7 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
return true; 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<CScript, int64> > vecSend; vector< pair<CScript, int64> > vecSend;
vecSend.push_back(make_pair(scriptPubKey, nValue)); 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 // 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) 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 // 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 // duration of this scope. This is the only place where this optimization
// maybe makes sense; please don't do it anywhere else. // 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 // Take key pair from key pool so it won't be used again
reservekey.KeepKey(); reservekey.KeepKey();
@ -851,11 +874,15 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
set<CWalletTx*> setCoins; set<CWalletTx*> setCoins;
BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
{ {
CWalletTx &pcoin = mapWallet[txin.prevout.hash]; CWalletTx &coin = mapWallet[txin.prevout.hash];
pcoin.MarkSpent(txin.prevout.n); coin.pwallet = this;
pcoin.WriteToDisk(); coin.MarkSpent(txin.prevout.n);
vWalletUpdated.push_back(pcoin.GetHash()); coin.WriteToDisk();
vWalletUpdated.push_back(coin.GetHash());
} }
if (fFileBacked)
delete pwalletdb;
} }
// Track how many getdata requests our transaction gets // Track how many getdata requests our transaction gets
@ -879,9 +906,9 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
// requires cs_main lock // 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; int64 nFeeRequired;
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, 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 // 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 // Check amount
if (nValue <= 0) 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; fFirstRunRet = false;
if (!CWalletDB("cr+").LoadWallet()) if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this))
return false; return false;
fFirstRunRet = vchDefaultKey.empty(); fFirstRunRet = vchDefaultKey.empty();
@ -944,17 +973,52 @@ bool LoadWallet(bool& fFirstRunRet)
// Create new keyUser and set as default key // Create new keyUser and set as default key
RandAddSeedPerfmon(); RandAddSeedPerfmon();
CWalletDB walletdb;
vchDefaultKey = GetKeyFromKeyPool(); vchDefaultKey = GetKeyFromKeyPool();
walletdb.WriteDefaultKey(vchDefaultKey); if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); return false;
CWalletDB(strWalletFile).WriteDefaultKey(keyUser.GetPubKey());
} }
CreateThread(ThreadFlushWalletDB, NULL); CreateThread(ThreadFlushWalletDB, &strWalletFile);
return true; 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<uint256, CWalletTx>::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; nIndex = -1;
keypool.vchPubKey.clear(); keypool.vchPubKey.clear();
@ -962,6 +1026,8 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool) CRITICAL_BLOCK(cs_setKeyPool)
{ {
CWalletDB walletdb(strWalletFile);
// Top up key pool // Top up key pool
int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0); int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
while (setKeyPool.size() < nTargetSize+1) while (setKeyPool.size() < nTargetSize+1)
@ -969,7 +1035,7 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
int64 nEnd = 1; int64 nEnd = 1;
if (!setKeyPool.empty()) if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1; 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"); throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
setKeyPool.insert(nEnd); setKeyPool.insert(nEnd);
printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size()); 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()); assert(!setKeyPool.empty());
nIndex = *(setKeyPool.begin()); nIndex = *(setKeyPool.begin());
setKeyPool.erase(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"); throw runtime_error("ReserveKeyFromKeyPool() : read failed");
if (!mapKeys.count(keypool.vchPubKey)) if (!mapKeys.count(keypool.vchPubKey))
throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); 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 // Remove from key pool
CRITICAL_BLOCK(cs_main) if (fFileBacked)
CRITICAL_BLOCK(cs_mapWallet)
{ {
Erase(make_pair(string("pool"), nIndex)); CWalletDB walletdb(strWalletFile);
CRITICAL_BLOCK(cs_main)
{
walletdb.ErasePool(nIndex);
}
} }
printf("keypool keep %"PRI64d"\n", nIndex); printf("keypool keep %"PRI64d"\n", nIndex);
} }
void CWalletDB::ReturnKey(int64 nIndex) void CWallet::ReturnKey(int64 nIndex)
{ {
// Return to key pool // Return to key pool
CRITICAL_BLOCK(cs_setKeyPool) CRITICAL_BLOCK(cs_setKeyPool)
@ -1007,32 +1076,30 @@ void CWalletDB::ReturnKey(int64 nIndex)
printf("keypool return %"PRI64d"\n", nIndex); printf("keypool return %"PRI64d"\n", nIndex);
} }
vector<unsigned char> GetKeyFromKeyPool() vector<unsigned char> CWallet::GetKeyFromKeyPool()
{ {
CWalletDB walletdb;
int64 nIndex = 0; int64 nIndex = 0;
CKeyPool keypool; CKeyPool keypool;
walletdb.ReserveKeyFromKeyPool(nIndex, keypool); ReserveKeyFromKeyPool(nIndex, keypool);
walletdb.KeepKey(nIndex); KeepKey(nIndex);
return keypool.vchPubKey; return keypool.vchPubKey;
} }
int64 GetOldestKeyPoolTime() int64 CWallet::GetOldestKeyPoolTime()
{ {
CWalletDB walletdb;
int64 nIndex = 0; int64 nIndex = 0;
CKeyPool keypool; CKeyPool keypool;
walletdb.ReserveKeyFromKeyPool(nIndex, keypool); ReserveKeyFromKeyPool(nIndex, keypool);
walletdb.ReturnKey(nIndex); ReturnKey(nIndex);
return keypool.nTime; return keypool.nTime;
} }
std::vector<unsigned char> CReserveKey::GetReservedKey() vector<unsigned char> CReserveKey::GetReservedKey()
{ {
if (nIndex == -1) if (nIndex == -1)
{ {
CKeyPool keypool; CKeyPool keypool;
CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool); pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
vchPubKey = keypool.vchPubKey; vchPubKey = keypool.vchPubKey;
} }
assert(!vchPubKey.empty()); assert(!vchPubKey.empty());
@ -1042,7 +1109,7 @@ std::vector<unsigned char> CReserveKey::GetReservedKey()
void CReserveKey::KeepKey() void CReserveKey::KeepKey()
{ {
if (nIndex != -1) if (nIndex != -1)
CWalletDB().KeepKey(nIndex); pwallet->KeepKey(nIndex);
nIndex = -1; nIndex = -1;
vchPubKey.clear(); vchPubKey.clear();
} }
@ -1050,7 +1117,7 @@ void CReserveKey::KeepKey()
void CReserveKey::ReturnKey() void CReserveKey::ReturnKey()
{ {
if (nIndex != -1) if (nIndex != -1)
CWalletDB::ReturnKey(nIndex); pwallet->ReturnKey(nIndex);
nIndex = -1; nIndex = -1;
vchPubKey.clear(); vchPubKey.clear();
} }

View file

@ -5,40 +5,205 @@
#define BITCOIN_WALLET_H #define BITCOIN_WALLET_H
#include "bignum.h" #include "bignum.h"
#include "key.h"
#include "script.h" #include "script.h"
class CWalletTx; class CWalletTx;
class CReserveKey; class CReserveKey;
class CWalletDB; class CWalletDB;
extern std::map<uint256, CWalletTx> mapWallet; class CWallet : public CKeyStore
extern std::vector<uint256> vWalletUpdated; {
extern CCriticalSection cs_mapWallet; private:
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
extern std::map<uint256, int> mapRequestCount;
extern CCriticalSection cs_mapRequestCount;
extern std::map<std::string, std::string> mapAddressBook; public:
extern CCriticalSection cs_mapAddressBook; bool fFileBacked;
std::string strWalletFile;
extern std::vector<unsigned char> vchDefaultKey; std::set<int64> setKeyPool;
extern CKey keyUser; CCriticalSection cs_setKeyPool;
bool AddToWallet(const CWalletTx& wtxIn); CWallet()
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); {
bool EraseFromWallet(uint256 hash); fFileBacked = false;
void WalletUpdateSpent(const COutPoint& prevout); }
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); CWallet(std::string strWalletFileIn)
void ReacceptWalletTransactions(); {
void ResendWalletTransactions(); strWalletFile = strWalletFileIn;
int64 GetBalance(); fFileBacked = true;
bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& 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);
mutable CCriticalSection cs_mapWallet;
std::map<uint256, CWalletTx> mapWallet;
std::vector<uint256> vWalletUpdated;
std::map<uint256, int> mapRequestCount;
mutable CCriticalSection cs_mapRequestCount;
std::map<std::string, std::string> mapAddressBook;
mutable CCriticalSection cs_mapAddressBook;
std::vector<unsigned char> 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<std::pair<CScript, int64> >& 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<unsigned char> 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<unsigned char> 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<uint256, int>::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<unsigned char> vchPubKey;
public:
CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
}
~CReserveKey()
{
if (!fShutdown)
ReturnKey();
}
void ReturnKey();
std::vector<unsigned char> GetReservedKey();
void KeepKey();
};
// //
@ -49,6 +214,8 @@ std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWal
class CWalletTx : public CMerkleTx class CWalletTx : public CMerkleTx
{ {
public: public:
const CWallet* pwallet;
std::vector<CMerkleTx> vtxPrev; std::vector<CMerkleTx> vtxPrev;
std::map<std::string, std::string> mapValue; std::map<std::string, std::string> mapValue;
std::vector<std::pair<std::string, std::string> > vOrderForm; std::vector<std::pair<std::string, std::string> > vOrderForm;
@ -73,24 +240,29 @@ public:
mutable int nLinesDisplayed; mutable int nLinesDisplayed;
mutable char fConfirmedDisplayed; mutable char fConfirmedDisplayed;
CWalletTx() 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(); vtxPrev.clear();
mapValue.clear(); mapValue.clear();
vOrderForm.clear(); vOrderForm.clear();
@ -116,7 +288,7 @@ public:
( (
CWalletTx* pthis = const_cast<CWalletTx*>(this); CWalletTx* pthis = const_cast<CWalletTx*>(this);
if (fRead) if (fRead)
pthis->Init(); pthis->Init(NULL);
char fSpent = false; char fSpent = false;
if (!fRead) if (!fRead)
@ -213,7 +385,7 @@ public:
return 0; return 0;
if (fDebitCached) if (fDebitCached)
return nDebitCached; return nDebitCached;
nDebitCached = CTransaction::GetDebit(); nDebitCached = pwallet->GetDebit(*this);
fDebitCached = true; fDebitCached = true;
return nDebitCached; return nDebitCached;
} }
@ -227,7 +399,7 @@ public:
// GetBalance can assume transactions in mapWallet won't change // GetBalance can assume transactions in mapWallet won't change
if (fUseCache && fCreditCached) if (fUseCache && fCreditCached)
return nCreditCached; return nCreditCached;
nCreditCached = CTransaction::GetCredit(); nCreditCached = pwallet->GetCredit(*this);
fCreditCached = true; fCreditCached = true;
return nCreditCached; return nCreditCached;
} }
@ -247,7 +419,7 @@ public:
if (!IsSpent(i)) if (!IsSpent(i))
{ {
const CTxOut &txout = vout[i]; const CTxOut &txout = vout[i];
nCredit += txout.GetCredit(); nCredit += pwallet->GetCredit(txout);
if (!MoneyRange(nCredit)) if (!MoneyRange(nCredit))
throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
} }
@ -263,7 +435,7 @@ public:
{ {
if (fChangeCached) if (fChangeCached)
return nChangeCached; return nChangeCached;
nChangeCached = CTransaction::GetChange(); nChangeCached = pwallet->GetChange(*this);
fChangeCached = true; fChangeCached = true;
return nChangeCached; return nChangeCached;
} }
@ -271,7 +443,7 @@ public:
void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<std::string /* address */, int64> >& listReceived, void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<std::string /* address */, int64> >& listReceived,
std::list<std::pair<std::string /* address */, int64> >& listSent, int64& nFee, std::string& strSentAccount) const; std::list<std::pair<std::string /* address */, int64> >& 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; int64& nSent, int64& nFee) const;
bool IsFromMe() const bool IsFromMe() const
@ -303,7 +475,7 @@ public:
return false; return false;
if (ptx->GetDepthInMainChain() >= 1) if (ptx->GetDepthInMainChain() >= 1)
continue; continue;
if (!ptx->IsFromMe()) if (!pwallet->IsFromMe(*ptx))
return false; return false;
if (mapPrev.empty()) if (mapPrev.empty())
@ -438,4 +610,6 @@ public:
) )
}; };
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
#endif #endif