aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bitcoin-qt.pro8
-rw-r--r--src/db.cpp168
-rw-r--r--src/db.h118
-rw-r--r--src/headers.h2
-rw-r--r--src/init.cpp37
-rw-r--r--src/init.h2
-rw-r--r--src/keystore.cpp33
-rw-r--r--src/keystore.h30
-rw-r--r--src/main.cpp1443
-rw-r--r--src/main.h567
-rw-r--r--src/net.cpp4
-rw-r--r--src/noui.h2
-rw-r--r--src/qt/addresstablemodel.cpp76
-rw-r--r--src/qt/addresstablemodel.h4
-rw-r--r--src/qt/bitcoin.cpp7
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/clientmodel.cpp29
-rw-r--r--src/qt/clientmodel.h5
-rw-r--r--src/qt/optionsmodel.cpp11
-rw-r--r--src/qt/optionsmodel.h7
-rw-r--r--src/qt/transactiondesc.cpp54
-rw-r--r--src/qt/transactiondesc.h3
-rw-r--r--src/qt/transactionrecord.cpp21
-rw-r--r--src/qt/transactionrecord.h4
-rw-r--r--src/qt/transactiontablemodel.cpp58
-rw-r--r--src/qt/transactiontablemodel.h5
-rw-r--r--src/qtui.h1
-rw-r--r--src/rpc.cpp149
-rw-r--r--src/script.cpp33
-rw-r--r--src/script.h8
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h4
-rw-r--r--src/wallet.cpp1176
-rw-r--r--src/wallet.h611
34 files changed, 2481 insertions, 2203 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index 7e918f144f..4036c14191 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -70,7 +70,9 @@ HEADERS += src/qt/bitcoingui.h \
src/qtui.h \
src/qt/transactiondesc.h \
src/qt/transactiondescdialog.h \
- src/qt/bitcoinamountfield.h
+ src/qt/bitcoinamountfield.h \
+ src/wallet.h \
+ src/keystore.h
SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiontablemodel.cpp \
src/qt/addresstablemodel.cpp \
@@ -101,7 +103,9 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
src/qt/transactiondesc.cpp \
src/qt/transactiondescdialog.cpp \
src/qt/bitcoinstrings.cpp \
- src/qt/bitcoinamountfield.cpp
+ src/qt/bitcoinamountfield.cpp \
+ src/wallet.cpp \
+ src/keystore.cpp
RESOURCES += \
src/qt/bitcoin.qrc
diff --git a/src/db.cpp b/src/db.cpp
index a7fb4bd6ea..f044355a35 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -5,14 +5,12 @@
#include "headers.h"
#include "db.h"
#include "net.h"
-#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;
using namespace boost;
-void ThreadFlushWalletDB(void* parg);
-
unsigned int nWalletDBUpdated;
uint64 nAccountingEntryNumber = 0;
@@ -151,7 +149,7 @@ void CDB::Close()
--mapFileUseCount[strFile];
}
-void CloseDb(const string& strFile)
+void static CloseDb(const string& strFile)
{
CRITICAL_BLOCK(cs_db)
{
@@ -360,7 +358,7 @@ bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
}
-CBlockIndex* InsertBlockIndex(uint256 hash)
+CBlockIndex static * InsertBlockIndex(uint256 hash)
{
if (hash == 0)
return NULL;
@@ -585,8 +583,19 @@ bool LoadAddresses()
// CWalletDB
//
-static set<int64> setKeyPool;
-static CCriticalSection cs_setKeyPool;
+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)
{
@@ -661,9 +670,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;
vector<uint256> vWalletUpgrade;
@@ -675,8 +684,8 @@ bool CWalletDB::LoadWallet()
#endif
//// todo: shouldn't we catch exceptions and try to recover and continue?
- CRITICAL_BLOCK(cs_mapWallet)
- CRITICAL_BLOCK(cs_mapKeys)
+ CRITICAL_BLOCK(pwallet->cs_mapWallet)
+ CRITICAL_BLOCK(pwallet->cs_mapKeys)
{
// Get cursor
Dbc* pcursor = GetCursor();
@@ -703,14 +712,15 @@ bool CWalletDB::LoadWallet()
{
string strAddress;
ssKey >> strAddress;
- ssValue >> mapAddressBook[strAddress];
+ ssValue >> pwallet->mapAddressBook[strAddress];
}
else if (strType == "tx")
{
uint256 hash;
ssKey >> hash;
- CWalletTx& wtx = mapWallet[hash];
+ CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx;
+ wtx.pwallet = pwallet;
if (wtx.GetHash() != hash)
printf("Error in wallet.dat, hash mismatch\n");
@@ -761,18 +771,18 @@ bool CWalletDB::LoadWallet()
else
ssValue >> wkey;
- mapKeys[vchPubKey] = wkey.vchPrivKey;
+ pwallet->mapKeys[vchPubKey] = wkey.vchPrivKey;
mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
}
else if (strType == "defaultkey")
{
- ssValue >> vchDefaultKey;
+ ssValue >> pwallet->vchDefaultKey;
}
else if (strType == "pool")
{
int64 nIndex;
ssKey >> nIndex;
- setKeyPool.insert(nIndex);
+ pwallet->setKeyPool.insert(nIndex);
}
else if (strType == "version")
{
@@ -804,7 +814,7 @@ bool CWalletDB::LoadWallet()
}
BOOST_FOREACH(uint256 hash, vWalletUpgrade)
- WriteTx(hash, mapWallet[hash]);
+ WriteTx(hash, pwallet->mapWallet[hash]);
printf("nFileVersion = %d\n", nFileVersion);
printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
@@ -832,36 +842,9 @@ bool CWalletDB::LoadWallet()
return true;
}
-bool LoadWallet(bool& fFirstRunRet)
-{
- fFirstRunRet = false;
- if (!CWalletDB("cr+").LoadWallet())
- return false;
- fFirstRunRet = vchDefaultKey.empty();
-
- if (mapKeys.count(vchDefaultKey))
- {
- // Set keyUser
- keyUser.SetPubKey(vchDefaultKey);
- keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
- }
- else
- {
- // Create new keyUser and set as default key
- RandAddSeedPerfmon();
-
- CWalletDB walletdb;
- vchDefaultKey = GetKeyFromKeyPool();
- walletdb.WriteDefaultKey(vchDefaultKey);
- walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
- }
-
- CreateThread(ThreadFlushWalletDB, NULL);
- return true;
-}
-
void ThreadFlushWalletDB(void* parg)
{
+ const string& strFile = ((const string*)parg)[0];
static bool fOneThread;
if (fOneThread)
return;
@@ -897,7 +880,6 @@ void ThreadFlushWalletDB(void* parg)
if (nRefCount == 0 && !fShutdown)
{
- string strFile = "wallet.dat";
map<string, int>::iterator mi = mapFileUseCount.find(strFile);
if (mi != mapFileUseCount.end())
{
@@ -920,26 +902,27 @@ void ThreadFlushWalletDB(void* parg)
}
}
-void BackupWallet(const string& strDest)
+bool BackupWallet(const CWallet& wallet, const string& strDest)
{
+ if (!wallet.fFileBacked)
+ return false;
while (!fShutdown)
{
CRITICAL_BLOCK(cs_db)
{
- const string strFile = "wallet.dat";
- if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
+ if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
{
// Flush log data to the dat file
- CloseDb(strFile);
+ CloseDb(wallet.strWalletFile);
dbenv.txn_checkpoint(0, 0, 0);
- dbenv.lsn_reset(strFile.c_str(), 0);
- mapFileUseCount.erase(strFile);
+ dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
+ mapFileUseCount.erase(wallet.strWalletFile);
// Copy wallet.dat
- filesystem::path pathSrc(GetDataDir() + "/" + strFile);
+ filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
filesystem::path pathDest(strDest);
if (filesystem::is_directory(pathDest))
- pathDest = pathDest / strFile;
+ pathDest = pathDest / wallet.strWalletFile;
#if BOOST_VERSION >= 104000
filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
#else
@@ -947,83 +930,10 @@ void BackupWallet(const string& strDest)
#endif
printf("copied wallet.dat to %s\n", pathDest.string().c_str());
- return;
+ return true;
}
}
Sleep(100);
}
-}
-
-
-void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
-{
- nIndex = -1;
- keypool.vchPubKey.clear();
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapWallet)
- CRITICAL_BLOCK(cs_setKeyPool)
- {
- // Top up key pool
- int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
- while (setKeyPool.size() < nTargetSize+1)
- {
- int64 nEnd = 1;
- if (!setKeyPool.empty())
- nEnd = *(--setKeyPool.end()) + 1;
- if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey())))
- throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
- setKeyPool.insert(nEnd);
- printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
- }
-
- // Get the oldest key
- assert(!setKeyPool.empty());
- nIndex = *(setKeyPool.begin());
- setKeyPool.erase(setKeyPool.begin());
- if (!Read(make_pair(string("pool"), nIndex), keypool))
- throw runtime_error("ReserveKeyFromKeyPool() : read failed");
- if (!mapKeys.count(keypool.vchPubKey))
- throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
- assert(!keypool.vchPubKey.empty());
- printf("keypool reserve %"PRI64d"\n", nIndex);
- }
-}
-
-void CWalletDB::KeepKey(int64 nIndex)
-{
- // Remove from key pool
- CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapWallet)
- {
- Erase(make_pair(string("pool"), nIndex));
- }
- printf("keypool keep %"PRI64d"\n", nIndex);
-}
-
-void CWalletDB::ReturnKey(int64 nIndex)
-{
- // Return to key pool
- CRITICAL_BLOCK(cs_setKeyPool)
- setKeyPool.insert(nIndex);
- printf("keypool return %"PRI64d"\n", nIndex);
-}
-
-vector<unsigned char> GetKeyFromKeyPool()
-{
- CWalletDB walletdb;
- int64 nIndex = 0;
- CKeyPool keypool;
- walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
- walletdb.KeepKey(nIndex);
- return keypool.vchPubKey;
-}
-
-int64 GetOldestKeyPoolTime()
-{
- CWalletDB walletdb;
- int64 nIndex = 0;
- CKeyPool keypool;
- walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
- walletdb.ReturnKey(nIndex);
- return keypool.nTime;
+ return false;
}
diff --git a/src/db.h b/src/db.h
index 9826194ed0..b89b34e009 100644
--- a/src/db.h
+++ b/src/db.h
@@ -12,33 +12,25 @@
#include <db_cxx.h>
-class CTransaction;
class CTxIndex;
class CDiskBlockIndex;
class CDiskTxPos;
class COutPoint;
-class CUser;
-class CReview;
class CAddress;
class CWalletTx;
+class CWallet;
class CAccount;
class CAccountingEntry;
class CBlockLocator;
-extern std::map<std::string, std::string> mapAddressBook;
-extern CCriticalSection cs_mapAddressBook;
-extern std::vector<unsigned char> vchDefaultKey;
-extern bool fClient;
-extern int nBestHeight;
-
extern unsigned int nWalletDBUpdated;
extern DbEnv dbenv;
extern void DBFlush(bool fShutdown);
-extern std::vector<unsigned char> GetKeyFromKeyPool();
-extern int64 GetOldestKeyPoolTime();
+void ThreadFlushWalletDB(void* parg);
+bool BackupWallet(const CWallet& wallet, const std::string& strDest);
@@ -321,9 +313,6 @@ bool LoadAddresses();
-
-
-
class CKeyPool
{
public:
@@ -356,7 +345,7 @@ public:
class CWalletDB : public CDB
{
public:
- CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode)
+ CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
{
}
private:
@@ -369,23 +358,9 @@ public:
return Read(std::make_pair(std::string("name"), strAddress), strName);
}
- bool WriteName(const std::string& strAddress, const std::string& strName)
- {
- CRITICAL_BLOCK(cs_mapAddressBook)
- mapAddressBook[strAddress] = strName;
- nWalletDBUpdated++;
- return Write(std::make_pair(std::string("name"), strAddress), strName);
- }
+ bool WriteName(const std::string& strAddress, const std::string& strName);
- bool EraseName(const std::string& strAddress)
- {
- // This should only be used for sending addresses, never for receiving addresses,
- // receiving addresses must always have an address book entry if they're not change return.
- CRITICAL_BLOCK(cs_mapAddressBook)
- mapAddressBook.erase(strAddress);
- nWalletDBUpdated++;
- return Erase(std::make_pair(std::string("name"), strAddress));
- }
+ bool EraseName(const std::string& strAddress);
bool ReadTx(uint256 hash, CWalletTx& wtx)
{
@@ -435,11 +410,27 @@ public:
bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
{
- vchDefaultKey = vchPubKey;
nWalletDBUpdated++;
return Write(std::string("defaultkey"), vchPubKey);
}
+ bool ReadPool(int64 nPool, CKeyPool& keypool)
+ {
+ return Read(std::make_pair(std::string("pool"), nPool), keypool);
+ }
+
+ bool WritePool(int64 nPool, const CKeyPool& keypool)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("pool"), nPool), keypool);
+ }
+
+ bool ErasePool(int64 nPool)
+ {
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("pool"), nPool));
+ }
+
template<typename T>
bool ReadSetting(const std::string& strKey, T& value)
{
@@ -459,68 +450,7 @@ public:
int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
- bool LoadWallet();
-protected:
- void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
- void KeepKey(int64 nIndex);
- static void ReturnKey(int64 nIndex);
- friend class CReserveKey;
- friend std::vector<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()
- {
- if (nIndex == -1)
- {
- CKeyPool keypool;
- CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
- vchPubKey = keypool.vchPubKey;
- }
- assert(!vchPubKey.empty());
- return vchPubKey;
- }
-
- void KeepKey()
- {
- if (nIndex != -1)
- CWalletDB().KeepKey(nIndex);
- nIndex = -1;
- vchPubKey.clear();
- }
-
- void ReturnKey()
- {
- if (nIndex != -1)
- CWalletDB::ReturnKey(nIndex);
- nIndex = -1;
- vchPubKey.clear();
- }
+ bool LoadWallet(CWallet* pwallet);
};
#endif
diff --git a/src/headers.h b/src/headers.h
index 38d9566baa..02dba30ae2 100644
--- a/src/headers.h
+++ b/src/headers.h
@@ -91,10 +91,8 @@
#include "serialize.h"
#include "uint256.h"
#include "util.h"
-#include "key.h"
#include "bignum.h"
#include "base58.h"
-#include "script.h"
#include "main.h"
#ifdef GUI
#include "uibase.h"
diff --git a/src/init.cpp b/src/init.cpp
index cbd9fc0219..e4605a2b42 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -7,13 +7,15 @@
#include "net.h"
#include "init.h"
#include "strlcpy.h"
-#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
using namespace std;
using namespace boost;
+CWallet* pwalletMain;
+
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
@@ -46,6 +48,8 @@ void Shutdown(void* parg)
StopNode();
DBFlush(true);
boost::filesystem::remove(GetPidFile());
+ UnregisterWallet(pwalletMain);
+ delete pwalletMain;
CreateThread(ExitTimeout, NULL);
Sleep(50);
printf("Bitcoin exiting\n\n");
@@ -137,10 +141,19 @@ bool AppInit2(int argc, char* argv[])
if (mapArgs.count("-datadir"))
{
- filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
- strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
+ if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"])))
+ {
+ filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
+ strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
+ }
+ else
+ {
+ fprintf(stderr, "Error: Specified directory does not exist\n");
+ Shutdown(NULL);
+ }
}
+
ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
if (mapArgs.count("-?") || mapArgs.count("--help"))
@@ -372,16 +385,19 @@ bool AppInit2(int argc, char* argv[])
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
- if (!LoadWallet(fFirstRun))
+ pwalletMain = new CWallet("wallet.dat");
+ if (!pwalletMain->LoadWallet(fFirstRun))
strErrors += _("Error loading wallet.dat \n");
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ RegisterWallet(pwalletMain);
+
CBlockIndex *pindexRescan = pindexBest;
if (GetBoolArg("-rescan"))
pindexRescan = pindexGenesisBlock;
else
{
- CWalletDB walletdb;
+ CWalletDB walletdb("wallet.dat");
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex();
@@ -390,7 +406,7 @@ bool AppInit2(int argc, char* argv[])
{
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
- ScanForWalletTransactions(pindexRescan, true);
+ pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
@@ -399,10 +415,11 @@ bool AppInit2(int argc, char* argv[])
//// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
- printf("mapKeys.size() = %d\n", mapKeys.size());
+ printf("mapKeys.size() = %d\n", pwalletMain->mapKeys.size());
+ printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
- printf("mapWallet.size() = %d\n", mapWallet.size());
- printf("mapAddressBook.size() = %d\n", mapAddressBook.size());
+ printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
+ printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
if (!strErrors.empty())
{
@@ -411,7 +428,7 @@ bool AppInit2(int argc, char* argv[])
}
// Add wallet transactions that aren't already in a block to mapTransactions
- ReacceptWalletTransactions();
+ pwalletMain->ReacceptWalletTransactions();
//
// Parameters
diff --git a/src/init.h b/src/init.h
index 61b2728576..a02260c293 100644
--- a/src/init.h
+++ b/src/init.h
@@ -4,6 +4,8 @@
#ifndef BITCOIN_INIT_H
#define BITCOIN_INIT_H
+extern CWallet* pwalletMain;
+
void Shutdown(void* parg);
bool AppInit(int argc, char* argv[]);
bool AppInit2(int argc, char* argv[]);
diff --git a/src/keystore.cpp b/src/keystore.cpp
new file mode 100644
index 0000000000..7dd045fe5f
--- /dev/null
+++ b/src/keystore.cpp
@@ -0,0 +1,33 @@
+// Copyright (c) 2009-2011 Satoshi Nakamoto & Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+#include "headers.h"
+#include "db.h"
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// mapKeys
+//
+
+std::vector<unsigned char> CKeyStore::GenerateNewKey()
+{
+ RandAddSeedPerfmon();
+ CKey key;
+ key.MakeNewKey();
+ if (!AddKey(key))
+ throw std::runtime_error("GenerateNewKey() : AddKey failed");
+ return key.GetPubKey();
+}
+
+bool CKeyStore::AddKey(const CKey& key)
+{
+ CRITICAL_BLOCK(cs_mapKeys)
+ {
+ mapKeys[key.GetPubKey()] = key.GetPrivKey();
+ mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
+ }
+}
+
diff --git a/src/keystore.h b/src/keystore.h
new file mode 100644
index 0000000000..6080d7d7f5
--- /dev/null
+++ b/src/keystore.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2009-2011 Satoshi Nakamoto & Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_KEYSTORE_H
+#define BITCOIN_KEYSTORE_H
+
+class CKeyStore
+{
+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);
+ }
+ bool GetPrivKey(const std::vector<unsigned char> &vchPubKey, CPrivKey& keyOut) const
+ {
+ std::map<std::vector<unsigned char>, CPrivKey>::const_iterator mi = mapKeys.find(vchPubKey);
+ if (mi != mapKeys.end())
+ {
+ keyOut = (*mi).second;
+ return true;
+ }
+ return false;
+ }
+ std::vector<unsigned char> GenerateNewKey();
+};
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index 2dbbd674a7..54902e82eb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,7 +6,7 @@
#include "net.h"
#include "init.h"
#include "cryptopp/sha.h"
-#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
using namespace std;
@@ -16,8 +16,14 @@ using namespace boost;
// Global state
//
+CCriticalSection cs_setpwalletRegistered;
+set<CWallet*> setpwalletRegistered;
+
CCriticalSection cs_main;
+CCriticalSection cs_mapPubKeys;
+map<uint160, vector<unsigned char> > mapPubKeys;
+
map<uint256, CTransaction> mapTransactions;
CCriticalSection cs_mapTransactions;
unsigned int nTransactionsUpdated = 0;
@@ -42,22 +48,6 @@ multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
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;
-
-vector<unsigned char> vchDefaultKey;
double dHashesPerSec;
int64 nHPSTimerStart;
@@ -84,151 +74,82 @@ int fUseUPnP = false;
//////////////////////////////////////////////////////////////////////////////
//
-// mapKeys
+// dispatching functions
//
-bool AddKey(const CKey& key)
+void RegisterWallet(CWallet* pwalletIn)
{
- CRITICAL_BLOCK(cs_mapKeys)
+ CRITICAL_BLOCK(cs_setpwalletRegistered)
{
- mapKeys[key.GetPubKey()] = key.GetPrivKey();
- mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
+ setpwalletRegistered.insert(pwalletIn);
}
- return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey());
}
-vector<unsigned char> GenerateNewKey()
+void UnregisterWallet(CWallet* pwalletIn)
{
- RandAddSeedPerfmon();
- CKey key;
- key.MakeNewKey();
- if (!AddKey(key))
- throw runtime_error("GenerateNewKey() : AddKey failed");
- return key.GetPubKey();
+ CRITICAL_BLOCK(cs_setpwalletRegistered)
+ {
+ setpwalletRegistered.erase(pwalletIn);
+ }
}
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// mapWallet
-//
-
-bool AddToWallet(const CWalletTx& wtxIn)
+bool static IsFromMe(CTransaction& tx)
{
- uint256 hash = wtxIn.GetHash();
- CRITICAL_BLOCK(cs_mapWallet)
- {
- // 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));
- CWalletTx& wtx = (*ret.first).second;
- bool fInsertedNew = ret.second;
- if (fInsertedNew)
- wtx.nTimeReceived = GetAdjustedTime();
-
- bool fUpdated = false;
- if (!fInsertedNew)
- {
- // Merge
- if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
- {
- wtx.hashBlock = wtxIn.hashBlock;
- fUpdated = true;
- }
- if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
- {
- wtx.vMerkleBranch = wtxIn.vMerkleBranch;
- wtx.nIndex = wtxIn.nIndex;
- fUpdated = true;
- }
- if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
- {
- wtx.fFromMe = wtxIn.fFromMe;
- fUpdated = true;
- }
- fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
- }
-
- //// debug print
- printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ if (pwallet->IsFromMe(tx))
+ return true;
+ return false;
+}
- // Write to disk
- if (fInsertedNew || fUpdated)
- if (!wtx.WriteToDisk())
- return false;
+bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ if (pwallet->GetTransaction(hashTx,wtx))
+ return true;
+ return false;
+}
- // If default receiving address gets used, replace it with a new one
- CScript scriptDefaultKey;
- scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- {
- if (txout.scriptPubKey == scriptDefaultKey)
- {
- CWalletDB walletdb;
- vchDefaultKey = GetKeyFromKeyPool();
- walletdb.WriteDefaultKey(vchDefaultKey);
- walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
- }
- }
+void static EraseFromWallets(uint256 hash)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->EraseFromWallet(hash);
+}
- // Notify UI
- vWalletUpdated.push_back(hash);
- }
+void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
+}
- // Refresh UI
- MainFrameRepaint();
- return true;
+void static SetBestChain(const CBlockLocator& loc)
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->SetBestChain(loc);
}
-bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false)
+void static UpdatedTransaction(const uint256& hashTx)
{
- uint256 hash = tx.GetHash();
- bool fExisted = mapWallet.count(hash);
- if (fExisted && !fUpdate) return false;
- if (fExisted || tx.IsMine() || tx.IsFromMe())
- {
- CWalletTx wtx(tx);
- // Get merkle branch if transaction was found in a block
- if (pblock)
- wtx.SetMerkleBranch(pblock);
- return AddToWallet(wtx);
- }
- return false;
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->UpdatedTransaction(hashTx);
}
-bool EraseFromWallet(uint256 hash)
+void static PrintWallets(const CBlock& block)
{
- CRITICAL_BLOCK(cs_mapWallet)
- {
- if (mapWallet.erase(hash))
- CWalletDB().EraseTx(hash);
- }
- return true;
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->PrintWallet(block);
}
-void WalletUpdateSpent(const COutPoint& prevout)
+void static Inventory(const uint256& hash)
{
- // Anytime a signature is successfully verified, it's proof the outpoint is spent.
- // Update the wallet spent flag if it doesn't know due to wallet.dat being
- // restored from backup or the user making copies of wallet.dat.
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
- {
- CWalletTx& wtx = (*mi).second;
- if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine())
- {
- printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
- wtx.MarkSpent(prevout.n);
- wtx.WriteToDisk();
- vWalletUpdated.push_back(prevout.hash);
- }
- }
- }
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->Inventory(hash);
}
+void static ResendWalletTransactions()
+{
+ BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
+ pwallet->ResendWalletTransactions();
+}
@@ -241,7 +162,7 @@ void WalletUpdateSpent(const COutPoint& prevout)
// mapOrphanTransactions
//
-void AddOrphanTx(const CDataStream& vMsg)
+void static AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
@@ -253,7 +174,7 @@ void AddOrphanTx(const CDataStream& vMsg)
mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
}
-void EraseOrphanTx(uint256 hash)
+void static EraseOrphanTx(uint256 hash)
{
if (!mapOrphanTransactions.count(hash))
return;
@@ -315,190 +236,6 @@ bool CTransaction::ReadFromDisk(COutPoint prevout)
return ReadFromDisk(txdb, prevout, txindex);
}
-bool CTxIn::IsMine() const
-{
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (prevout.n < prev.vout.size())
- if (prev.vout[prevout.n].IsMine())
- return true;
- }
- }
- return false;
-}
-
-int64 CTxIn::GetDebit() const
-{
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (prevout.n < prev.vout.size())
- if (prev.vout[prevout.n].IsMine())
- return prev.vout[prevout.n].nValue;
- }
- }
- return 0;
-}
-
-int64 CWalletTx::GetTxTime() const
-{
- if (!fTimeReceivedIsTxTime && hashBlock != 0)
- {
- // If we did not receive the transaction directly, we rely on the block's
- // time to figure out when it happened. We use the median over a range
- // of blocks to try to filter out inaccurate block times.
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
- if (pindex)
- return pindex->GetMedianTime();
- }
- }
- return nTimeReceived;
-}
-
-int CWalletTx::GetRequestCount() const
-{
- // Returns -1 if it wasn't being tracked
- int nRequests = -1;
- CRITICAL_BLOCK(cs_mapRequestCount)
- {
- if (IsCoinBase())
- {
- // Generated block
- if (hashBlock != 0)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
- if (mi != mapRequestCount.end())
- nRequests = (*mi).second;
- }
- }
- else
- {
- // Did anyone request this transaction?
- map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());
- if (mi != mapRequestCount.end())
- {
- nRequests = (*mi).second;
-
- // How about the block it's in?
- if (nRequests == 0 && hashBlock != 0)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
- if (mi != mapRequestCount.end())
- nRequests = (*mi).second;
- else
- nRequests = 1; // If it's in someone else's block it must have got out
- }
- }
- }
- }
- return nRequests;
-}
-
-void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<string, int64> >& listReceived,
- list<pair<string, int64> >& listSent, int64& nFee, string& strSentAccount) const
-{
- nGeneratedImmature = nGeneratedMature = nFee = 0;
- listReceived.clear();
- listSent.clear();
- strSentAccount = strFromAccount;
-
- if (IsCoinBase())
- {
- if (GetBlocksToMaturity() > 0)
- nGeneratedImmature = CTransaction::GetCredit();
- else
- nGeneratedMature = GetCredit();
- return;
- }
-
- // Compute fee:
- int64 nDebit = GetDebit();
- if (nDebit > 0) // debit>0 means we signed/sent this transaction
- {
- int64 nValueOut = GetValueOut();
- nFee = nDebit - nValueOut;
- }
-
- // Sent/received. Standard client will never generate a send-to-multiple-recipients,
- // but non-standard clients might (so return a list of address/amount pairs)
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- string address;
- uint160 hash160;
- vector<unsigned char> vchPubKey;
- if (ExtractHash160(txout.scriptPubKey, hash160))
- address = Hash160ToAddress(hash160);
- else if (ExtractPubKey(txout.scriptPubKey, false, vchPubKey))
- address = PubKeyToAddress(vchPubKey);
- else
- {
- printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
- this->GetHash().ToString().c_str());
- address = " unknown ";
- }
-
- // Don't report 'change' txouts
- if (nDebit > 0 && txout.IsChange())
- continue;
-
- if (nDebit > 0)
- listSent.push_back(make_pair(address, txout.nValue));
-
- if (txout.IsMine())
- listReceived.push_back(make_pair(address, txout.nValue));
- }
-
-}
-
-void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
- int64& nSent, int64& nFee) const
-{
- nGenerated = nReceived = nSent = nFee = 0;
-
- int64 allGeneratedImmature, allGeneratedMature, allFee;
- allGeneratedImmature = allGeneratedMature = allFee = 0;
- string strSentAccount;
- list<pair<string, int64> > listReceived;
- list<pair<string, int64> > listSent;
- GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
-
- if (strAccount == "")
- nGenerated = allGeneratedMature;
- if (strAccount == strSentAccount)
- {
- BOOST_FOREACH(const PAIRTYPE(string,int64)& s, listSent)
- nSent += s.second;
- nFee = allFee;
- }
- CRITICAL_BLOCK(cs_mapAddressBook)
- {
- BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
- {
- if (mapAddressBook.count(r.first))
- {
- if (mapAddressBook[r.first] == strAccount)
- {
- nReceived += r.second;
- }
- }
- else if (strAccount.empty())
- {
- nReceived += r.second;
- }
- }
- }
-}
-
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@ -554,69 +291,6 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
-void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
-{
- vtxPrev.clear();
-
- const int COPY_DEPTH = 3;
- if (SetMerkleBranch() < COPY_DEPTH)
- {
- vector<uint256> vWorkQueue;
- BOOST_FOREACH(const CTxIn& txin, vin)
- vWorkQueue.push_back(txin.prevout.hash);
-
- // This critsect is OK because txdb is already open
- CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, const CMerkleTx*> mapWalletPrev;
- set<uint256> setAlreadyDone;
- for (int i = 0; i < vWorkQueue.size(); i++)
- {
- uint256 hash = vWorkQueue[i];
- if (setAlreadyDone.count(hash))
- continue;
- setAlreadyDone.insert(hash);
-
- CMerkleTx tx;
- if (mapWallet.count(hash))
- {
- tx = mapWallet[hash];
- BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
- mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
- }
- else if (mapWalletPrev.count(hash))
- {
- tx = *mapWalletPrev[hash];
- }
- else if (!fClient && txdb.ReadDiskTx(hash, tx))
- {
- ;
- }
- else
- {
- printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
- continue;
- }
-
- int nDepth = tx.SetMerkleBranch();
- vtxPrev.push_back(tx);
-
- if (nDepth < COPY_DEPTH)
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- vWorkQueue.push_back(txin.prevout.hash);
- }
- }
- }
-
- reverse(vtxPrev.begin(), vtxPrev.end());
-}
-
-
-
-
-
-
-
@@ -758,7 +432,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
- if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe())
+ if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this))
return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
if (fDebug)
printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
@@ -781,12 +455,17 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
///// are we sure this is ok when loading transactions or restoring block txes
// If updated, erase old tx from wallet
if (ptxOld)
- EraseFromWallet(ptxOld->GetHash());
+ EraseFromWallets(ptxOld->GetHash());
printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
return true;
}
+bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
+{
+ CTxDB txdb("r");
+ return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
+}
bool CTransaction::AddToMemoryPoolUnchecked()
{
@@ -870,6 +549,12 @@ bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
}
}
+bool CMerkleTx::AcceptToMemoryPool()
+{
+ CTxDB txdb("r");
+ return AcceptToMemoryPool(txdb);
+}
+
bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
@@ -891,148 +576,10 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
return false;
}
-int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
-{
- int ret = 0;
-
- CBlockIndex* pindex = pindexStart;
- CRITICAL_BLOCK(cs_mapWallet)
- {
- while (pindex)
- {
- CBlock block;
- block.ReadFromDisk(pindex, true);
- BOOST_FOREACH(CTransaction& tx, block.vtx)
- {
- if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
- ret++;
- }
- pindex = pindex->pnext;
- }
- }
- return ret;
-}
-
-void ReacceptWalletTransactions()
+bool CWalletTx::AcceptWalletTransaction()
{
CTxDB txdb("r");
- bool fRepeat = true;
- while (fRepeat) CRITICAL_BLOCK(cs_mapWallet)
- {
- fRepeat = false;
- vector<CDiskTxPos> vMissingTx;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
- {
- CWalletTx& wtx = item.second;
- if (wtx.IsCoinBase() && wtx.IsSpent(0))
- continue;
-
- CTxIndex txindex;
- bool fUpdated = false;
- if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
- {
- // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
- if (txindex.vSpent.size() != wtx.vout.size())
- {
- printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
- continue;
- }
- for (int i = 0; i < txindex.vSpent.size(); i++)
- {
- if (wtx.IsSpent(i))
- continue;
- if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())
- {
- wtx.MarkSpent(i);
- fUpdated = true;
- vMissingTx.push_back(txindex.vSpent[i]);
- }
- }
- if (fUpdated)
- {
- printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
- wtx.MarkDirty();
- wtx.WriteToDisk();
- }
- }
- else
- {
- // Reaccept any txes of ours that aren't already in a block
- if (!wtx.IsCoinBase())
- wtx.AcceptWalletTransaction(txdb, false);
- }
- }
- if (!vMissingTx.empty())
- {
- // TODO: optimize this to scan just part of the block chain?
- if (ScanForWalletTransactions(pindexGenesisBlock))
- fRepeat = true; // Found missing transactions: re-do Reaccept.
- }
- }
-}
-
-
-void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
-{
- BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
- {
- if (!tx.IsCoinBase())
- {
- uint256 hash = tx.GetHash();
- if (!txdb.ContainsTx(hash))
- RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
- }
- }
- if (!IsCoinBase())
- {
- uint256 hash = GetHash();
- if (!txdb.ContainsTx(hash))
- {
- printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
- RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
- }
- }
-}
-
-void ResendWalletTransactions()
-{
- // Do this infrequently and randomly to avoid giving away
- // that these are our transactions.
- static int64 nNextTime;
- if (GetTime() < nNextTime)
- return;
- bool fFirst = (nNextTime == 0);
- nNextTime = GetTime() + GetRand(30 * 60);
- if (fFirst)
- return;
-
- // Only do it if there's been a new block since last time
- static int64 nLastTime;
- if (nTimeBestReceived < nLastTime)
- return;
- nLastTime = GetTime();
-
- // Rebroadcast any of our txes that aren't in a block yet
- printf("ResendWalletTransactions()\n");
- CTxDB txdb("r");
- CRITICAL_BLOCK(cs_mapWallet)
- {
- // Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
- {
- CWalletTx& wtx = item.second;
- // Don't rebroadcast until it's had plenty of time that
- // it should have gotten in already by now.
- if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
- }
- BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
- {
- CWalletTx& wtx = *item.second;
- wtx.RelayWalletTransaction(txdb);
- }
- }
+ return AcceptWalletTransaction(txdb);
}
int CTxIndex::GetDepthInMainChain() const
@@ -1079,7 +626,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
return true;
}
-uint256 GetOrphanRoot(const CBlock* pblock)
+uint256 static GetOrphanRoot(const CBlock* pblock)
{
// Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock))
@@ -1087,7 +634,7 @@ uint256 GetOrphanRoot(const CBlock* pblock)
return pblock->GetHash();
}
-int64 GetBlockValue(int nHeight, int64 nFees)
+int64 static GetBlockValue(int nHeight, int64 nFees)
{
int64 nSubsidy = 50 * COIN;
@@ -1097,7 +644,7 @@ int64 GetBlockValue(int nHeight, int64 nFees)
return nSubsidy + nFees;
}
-unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
+unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
{
const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
const int64 nTargetSpacing = 10 * 60;
@@ -1187,7 +734,7 @@ bool IsInitialBlockDownload()
pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
}
-void InvalidChainFound(CBlockIndex* pindexNew)
+void static InvalidChainFound(CBlockIndex* pindexNew)
{
if (pindexNew->bnChainWork > bnBestInvalidWork)
{
@@ -1463,12 +1010,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// Watch for transactions paying to me
BOOST_FOREACH(CTransaction& tx, vtx)
- AddToWalletIfInvolvingMe(tx, this, true);
+ SyncWithWallets(tx, this, true);
return true;
}
-bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
+bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{
printf("REORGANIZE\n");
@@ -1606,10 +1153,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
// Update best block in wallet (so we can detect restored wallets)
if (!IsInitialBlockDownload())
{
- CWalletDB walletdb;
const CBlockLocator locator(pindexNew);
- if (!walletdb.WriteBestBlock(locator))
- return error("SetBestChain() : WriteWalletBest failed");
+ ::SetBestChain(locator);
}
// New best block
@@ -1663,8 +1208,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
{
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
- CRITICAL_BLOCK(cs_mapWallet)
- vWalletUpdated.push_back(hashPrevBestCoinBase);
+ UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = vtx[0].GetHash();
}
@@ -1773,7 +1317,7 @@ bool CBlock::AcceptBlock()
return true;
}
-bool ProcessBlock(CNode* pfrom, CBlock* pblock)
+bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
@@ -1835,7 +1379,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
template<typename Stream>
-bool ScanMessageStart(Stream& s)
+bool static ScanMessageStart(Stream& s)
{
// Scan ahead to the next pchMessageStart, which should normally be immediately
// at the file pointer. Leaves file pointer at end of pchMessageStart.
@@ -2050,7 +1594,7 @@ void PrintBlockTree()
for (int i = 0; i < nCol; i++)
printf("| ");
printf("|\n");
- }
+ }
nPrevCol = nCol;
// print columns
@@ -2068,16 +1612,7 @@ void PrintBlockTree()
DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size());
- CRITICAL_BLOCK(cs_mapWallet)
- {
- if (mapWallet.count(block.vtx[0].GetHash()))
- {
- CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
- printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
- }
- }
- printf("\n");
-
+ PrintWallets(block);
// put the main timechain first
vector<CBlockIndex*>& vNext = mapNext[pindex];
@@ -2217,7 +1752,7 @@ bool CAlert::ProcessAlert()
//
-bool AlreadyHave(CTxDB& txdb, const CInv& inv)
+bool static AlreadyHave(CTxDB& txdb, const CInv& inv)
{
switch (inv.type)
{
@@ -2237,128 +1772,7 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv)
char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
-bool ProcessMessages(CNode* pfrom)
-{
- CDataStream& vRecv = pfrom->vRecv;
- if (vRecv.empty())
- return true;
- //if (fDebug)
- // printf("ProcessMessages(%u bytes)\n", vRecv.size());
-
- //
- // Message format
- // (4) message start
- // (12) command
- // (4) size
- // (4) checksum
- // (x) data
- //
-
- loop
- {
- // Scan for message start
- CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
- int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
- if (vRecv.end() - pstart < nHeaderSize)
- {
- if (vRecv.size() > nHeaderSize)
- {
- printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
- vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
- }
- break;
- }
- if (pstart - vRecv.begin() > 0)
- printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
- vRecv.erase(vRecv.begin(), pstart);
-
- // Read header
- vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
- CMessageHeader hdr;
- vRecv >> hdr;
- if (!hdr.IsValid())
- {
- printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
- continue;
- }
- string strCommand = hdr.GetCommand();
-
- // Message size
- unsigned int nMessageSize = hdr.nMessageSize;
- if (nMessageSize > MAX_SIZE)
- {
- printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
- continue;
- }
- if (nMessageSize > vRecv.size())
- {
- // Rewind and wait for rest of message
- vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
- break;
- }
-
- // Checksum
- if (vRecv.GetVersion() >= 209)
- {
- uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
- unsigned int nChecksum = 0;
- memcpy(&nChecksum, &hash, sizeof(nChecksum));
- if (nChecksum != hdr.nChecksum)
- {
- printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
- strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
- continue;
- }
- }
-
- // Copy message to its own buffer
- CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
- vRecv.ignore(nMessageSize);
-
- // Process message
- bool fRet = false;
- try
- {
- CRITICAL_BLOCK(cs_main)
- fRet = ProcessMessage(pfrom, strCommand, vMsg);
- if (fShutdown)
- return true;
- }
- catch (std::ios_base::failure& e)
- {
- if (strstr(e.what(), "end of data"))
- {
- // Allow exceptions from underlength message on vRecv
- printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "size too large"))
- {
- // Allow exceptions from overlong size
- printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
- }
- else
- {
- PrintExceptionContinue(&e, "ProcessMessage()");
- }
- }
- catch (std::exception& e) {
- PrintExceptionContinue(&e, "ProcessMessage()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ProcessMessage()");
- }
-
- if (!fRet)
- printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
- }
-
- vRecv.Compact();
- return true;
-}
-
-
-
-
-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;
RandAddSeedPerfmon();
@@ -2555,12 +1969,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
- CRITICAL_BLOCK(cs_mapRequestCount)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
- if (mi != mapRequestCount.end())
- (*mi).second++;
- }
+ Inventory(inv.hash);
}
}
@@ -2613,12 +2022,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
// Track requests for our stuff
- CRITICAL_BLOCK(cs_mapRequestCount)
- {
- map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
- if (mi != mapRequestCount.end())
- (*mi).second++;
- }
+ Inventory(inv.hash);
}
}
@@ -2706,7 +2110,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool fMissingInputs = false;
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{
- AddToWalletIfInvolvingMe(tx, NULL, true);
+ SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
@@ -2727,7 +2131,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (tx.AcceptToMemoryPool(true))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
- AddToWalletIfInvolvingMe(tx, NULL, true);
+ SyncWithWallets(tx, NULL, true);
RelayMessage(inv, vMsg);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
@@ -2804,7 +2208,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip))
- mapReuseKey[pfrom->addr.ip] = GetKeyFromKeyPool();
+ mapReuseKey[pfrom->addr.ip] = pwalletMain->GetKeyFromKeyPool();
// Send back approval of order and pubkey to use
CScript scriptPubKey;
@@ -2813,37 +2217,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
- else if (strCommand == "submitorder")
- {
- uint256 hashReply;
- vRecv >> hashReply;
-
- if (!GetBoolArg("-allowreceivebyip"))
- {
- pfrom->PushMessage("reply", hashReply, (int)2);
- return true;
- }
-
- CWalletTx wtxNew;
- vRecv >> wtxNew;
- wtxNew.fFromMe = false;
-
- // Broadcast
- if (!wtxNew.AcceptWalletTransaction())
- {
- pfrom->PushMessage("reply", hashReply, (int)1);
- return error("submitorder AcceptWalletTransaction() failed, returning error 1");
- }
- wtxNew.fTimeReceivedIsTxTime = true;
- AddToWallet(wtxNew);
- wtxNew.RelayWalletTransaction();
- mapReuseKey.erase(pfrom->addr.ip);
-
- // Send back confirmation
- pfrom->PushMessage("reply", hashReply, (int)0);
- }
-
-
else if (strCommand == "reply")
{
uint256 hashReply;
@@ -2900,12 +2273,123 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
}
+bool ProcessMessages(CNode* pfrom)
+{
+ CDataStream& vRecv = pfrom->vRecv;
+ if (vRecv.empty())
+ return true;
+ //if (fDebug)
+ // printf("ProcessMessages(%u bytes)\n", vRecv.size());
+ //
+ // Message format
+ // (4) message start
+ // (12) command
+ // (4) size
+ // (4) checksum
+ // (x) data
+ //
+ loop
+ {
+ // Scan for message start
+ CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
+ int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
+ if (vRecv.end() - pstart < nHeaderSize)
+ {
+ if (vRecv.size() > nHeaderSize)
+ {
+ printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
+ vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
+ }
+ break;
+ }
+ if (pstart - vRecv.begin() > 0)
+ printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
+ vRecv.erase(vRecv.begin(), pstart);
+ // Read header
+ vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
+ CMessageHeader hdr;
+ vRecv >> hdr;
+ if (!hdr.IsValid())
+ {
+ printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
+ continue;
+ }
+ string strCommand = hdr.GetCommand();
+ // Message size
+ unsigned int nMessageSize = hdr.nMessageSize;
+ if (nMessageSize > MAX_SIZE)
+ {
+ printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+ continue;
+ }
+ if (nMessageSize > vRecv.size())
+ {
+ // Rewind and wait for rest of message
+ vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
+ break;
+ }
+ // Checksum
+ if (vRecv.GetVersion() >= 209)
+ {
+ uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+ unsigned int nChecksum = 0;
+ memcpy(&nChecksum, &hash, sizeof(nChecksum));
+ if (nChecksum != hdr.nChecksum)
+ {
+ printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+ strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
+ continue;
+ }
+ }
+ // Copy message to its own buffer
+ CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
+ vRecv.ignore(nMessageSize);
+
+ // Process message
+ bool fRet = false;
+ try
+ {
+ CRITICAL_BLOCK(cs_main)
+ fRet = ProcessMessage(pfrom, strCommand, vMsg);
+ if (fShutdown)
+ return true;
+ }
+ catch (std::ios_base::failure& e)
+ {
+ if (strstr(e.what(), "end of data"))
+ {
+ // Allow exceptions from underlength message on vRecv
+ printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+ }
+ else if (strstr(e.what(), "size too large"))
+ {
+ // Allow exceptions from overlong size
+ printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+ }
+ else
+ {
+ PrintExceptionContinue(&e, "ProcessMessage()");
+ }
+ }
+ catch (std::exception& e) {
+ PrintExceptionContinue(&e, "ProcessMessage()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "ProcessMessage()");
+ }
+
+ if (!fRet)
+ printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
+ }
+
+ vRecv.Compact();
+ return true;
+}
bool SendMessages(CNode* pto, bool fSendTrickle)
@@ -3030,16 +2514,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// always trickle our own transactions
if (!fTrickleWait)
{
- TRY_CRITICAL_BLOCK(cs_mapWallet)
- {
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(inv.hash);
- if (mi != mapWallet.end())
- {
- CWalletTx& wtx = (*mi).second;
- if (wtx.fFromMe)
- fTrickleWait = true;
- }
- }
+ CWalletTx wtx;
+ if (GetTransaction(inv.hash, wtx))
+ if (wtx.fFromMe)
+ fTrickleWait = true;
}
if (fTrickleWait)
@@ -3112,57 +2590,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// BitcoinMiner
//
-void GenerateBitcoins(bool fGenerate)
-{
- if (fGenerateBitcoins != fGenerate)
- {
- fGenerateBitcoins = fGenerate;
- CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
- MainFrameRepaint();
- }
- if (fGenerateBitcoins)
- {
- int nProcessors = boost::thread::hardware_concurrency();
- printf("%d processors\n", nProcessors);
- if (nProcessors < 1)
- nProcessors = 1;
- if (fLimitProcessors && nProcessors > nLimitProcessors)
- nProcessors = nLimitProcessors;
- int nAddThreads = nProcessors - vnThreadsRunning[3];
- printf("Starting %d BitcoinMiner threads\n", nAddThreads);
- for (int i = 0; i < nAddThreads; i++)
- {
- if (!CreateThread(ThreadBitcoinMiner, NULL))
- printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
- Sleep(10);
- }
- }
-}
-
-void ThreadBitcoinMiner(void* parg)
-{
- try
- {
- vnThreadsRunning[3]++;
- BitcoinMiner();
- vnThreadsRunning[3]--;
- }
- catch (std::exception& e) {
- vnThreadsRunning[3]--;
- PrintException(&e, "ThreadBitcoinMiner()");
- } catch (...) {
- vnThreadsRunning[3]--;
- PrintException(NULL, "ThreadBitcoinMiner()");
- }
- UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
- nHPSTimerStart = 0;
- if (vnThreadsRunning[3] == 0)
- dHashesPerSec = 0;
- printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
-}
-
-
-int FormatHashBlocks(void* pbuffer, unsigned int len)
+int static FormatHashBlocks(void* pbuffer, unsigned int len)
{
unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64);
@@ -3195,7 +2623,7 @@ inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
// between calls, but periodically or if nNonce is 0xffff0000 or above,
// the block is rebuilt and nNonce starts over at zero.
//
-unsigned int ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
+unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
{
unsigned int& nNonce = *(unsigned int*)(pdata + 12);
for (;;)
@@ -3452,7 +2880,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash
}
-bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
+bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
{
uint256 hash = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
@@ -3477,8 +2905,8 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
reservekey.KeepKey();
// Track how many getdata requests this block gets
- CRITICAL_BLOCK(cs_mapRequestCount)
- mapRequestCount[pblock->GetHash()] = 0;
+ CRITICAL_BLOCK(wallet.cs_mapRequestCount)
+ wallet.mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node
if (!ProcessBlock(NULL, pblock))
@@ -3489,14 +2917,15 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
return true;
}
+void static ThreadBitcoinMiner(void* parg);
-void BitcoinMiner()
+void static BitcoinMiner(CWallet *pwallet)
{
printf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
// Each thread has its own key and counter
- CReserveKey reservekey;
+ CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
int64 nPrevTime = 0;
@@ -3572,7 +3001,7 @@ void BitcoinMiner()
assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL);
- CheckWork(pblock.get(), reservekey);
+ CheckWork(pblock.get(), *pwalletMain, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
break;
}
@@ -3633,421 +3062,53 @@ void BitcoinMiner()
}
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Actions
-//
-
-
-int64 GetBalance()
-{
- int64 nStart = GetTimeMillis();
-
- int64 nTotal = 0;
- CRITICAL_BLOCK(cs_mapWallet)
- {
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- {
- CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
- continue;
- nTotal += pcoin->GetAvailableCredit();
- }
- }
-
- //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
- return nTotal;
-}
-
-
-bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
+void static ThreadBitcoinMiner(void* parg)
{
- setCoinsRet.clear();
- nValueRet = 0;
-
- // List of values less than target
- pair<int64, pair<CWalletTx*,unsigned int> > coinLowestLarger;
- coinLowestLarger.first = INT64_MAX;
- coinLowestLarger.second.first = NULL;
- vector<pair<int64, pair<CWalletTx*,unsigned int> > > vValue;
- int64 nTotalLower = 0;
-
- CRITICAL_BLOCK(cs_mapWallet)
- {
- vector<CWalletTx*> vCoins;
- vCoins.reserve(mapWallet.size());
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
- vCoins.push_back(&(*it).second);
- random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
-
- BOOST_FOREACH(CWalletTx* pcoin, vCoins)
- {
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
- continue;
-
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
- continue;
-
- int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
- continue;
-
- for (int i = 0; i < pcoin->vout.size(); i++)
- {
- if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine())
- continue;
-
- int64 n = pcoin->vout[i].nValue;
-
- if (n <= 0)
- continue;
-
- pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
-
- if (n == nTargetValue)
- {
- setCoinsRet.insert(coin.second);
- nValueRet += coin.first;
- return true;
- }
- else if (n < nTargetValue + CENT)
- {
- vValue.push_back(coin);
- nTotalLower += n;
- }
- else if (n < coinLowestLarger.first)
- {
- coinLowestLarger = coin;
- }
- }
- }
- }
-
- if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
- {
- for (int i = 0; i < vValue.size(); ++i)
- {
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
- }
- return true;
- }
-
- if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
- {
- if (coinLowestLarger.second.first == NULL)
- return false;
- setCoinsRet.insert(coinLowestLarger.second);
- nValueRet += coinLowestLarger.first;
- return true;
- }
-
- if (nTotalLower >= nTargetValue + CENT)
- nTargetValue += CENT;
-
- // Solve subset sum by stochastic approximation
- sort(vValue.rbegin(), vValue.rend());
- vector<char> vfIncluded;
- vector<char> vfBest(vValue.size(), true);
- int64 nBest = nTotalLower;
-
- for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
- {
- vfIncluded.assign(vValue.size(), false);
- int64 nTotal = 0;
- bool fReachedTarget = false;
- for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
- {
- for (int i = 0; i < vValue.size(); i++)
- {
- if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
- {
- nTotal += vValue[i].first;
- vfIncluded[i] = true;
- if (nTotal >= nTargetValue)
- {
- fReachedTarget = true;
- if (nTotal < nBest)
- {
- nBest = nTotal;
- vfBest = vfIncluded;
- }
- nTotal -= vValue[i].first;
- vfIncluded[i] = false;
- }
- }
- }
- }
- }
-
- // If the next larger is still closer, return it
- if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
+ CWallet* pwallet = (CWallet*)parg;
+ try
{
- setCoinsRet.insert(coinLowestLarger.second);
- nValueRet += coinLowestLarger.first;
+ vnThreadsRunning[3]++;
+ BitcoinMiner(pwallet);
+ vnThreadsRunning[3]--;
}
- else {
- for (int i = 0; i < vValue.size(); i++)
- if (vfBest[i])
- {
- setCoinsRet.insert(vValue[i].second);
- nValueRet += vValue[i].first;
- }
-
- //// debug print
- printf("SelectCoins() best subset: ");
- for (int i = 0; i < vValue.size(); i++)
- if (vfBest[i])
- printf("%s ", FormatMoney(vValue[i].first).c_str());
- printf("total %s\n", FormatMoney(nBest).c_str());
+ catch (std::exception& e) {
+ vnThreadsRunning[3]--;
+ PrintException(&e, "ThreadBitcoinMiner()");
+ } catch (...) {
+ vnThreadsRunning[3]--;
+ PrintException(NULL, "ThreadBitcoinMiner()");
}
-
- return true;
-}
-
-bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
-{
- return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
+ UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
+ nHPSTimerStart = 0;
+ if (vnThreadsRunning[3] == 0)
+ dHashesPerSec = 0;
+ printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
}
-
-
-bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
{
- int64 nValue = 0;
- BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
- {
- if (nValue < 0)
- return false;
- nValue += s.second;
- }
- if (vecSend.empty() || nValue < 0)
- return false;
-
- CRITICAL_BLOCK(cs_main)
+ if (fGenerateBitcoins != fGenerate)
{
- // txdb must be opened before the mapWallet lock
- CTxDB txdb("r");
- CRITICAL_BLOCK(cs_mapWallet)
- {
- nFeeRet = nTransactionFee;
- loop
- {
- wtxNew.vin.clear();
- wtxNew.vout.clear();
- wtxNew.fFromMe = true;
-
- int64 nTotalValue = nValue + nFeeRet;
- double dPriority = 0;
- // vouts to the payees
- BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
- wtxNew.vout.push_back(CTxOut(s.second, s.first));
-
- // Choose coins to use
- set<pair<CWalletTx*,unsigned int> > setCoins;
- int64 nValueIn = 0;
- if (!SelectCoins(nTotalValue, setCoins, nValueIn))
- return false;
- BOOST_FOREACH(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins)
- {
- int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
- dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
- }
-
- int64 nChange = nValueIn - nValue - nFeeRet;
-
- // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
- // or until nChange becomes zero
- if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
- {
- int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
- nChange -= nMoveToFee;
- nFeeRet += nMoveToFee;
- }
-
- if (nChange > 0)
- {
- // Note: We use a new key here to keep it from being obvious which side is the change.
- // The drawback is that by not reusing a previous key, the change may be lost if a
- // backup is restored, if the backup doesn't have the new private key for the change.
- // If we reused the old key, it would be possible to add code to look for and
- // rediscover unknown transactions that were written with keys of ours to recover
- // post-backup change.
-
- // Reserve a new key pair from key pool
- vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
- assert(mapKeys.count(vchPubKey));
-
- // Fill a vout to ourself, using same address type as the payment
- CScript scriptChange;
- if (vecSend[0].first.GetBitcoinAddressHash160() != 0)
- scriptChange.SetBitcoinAddress(vchPubKey);
- else
- scriptChange << vchPubKey << OP_CHECKSIG;
-
- // Insert change txn at random position:
- vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
- wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
- }
- else
- reservekey.ReturnKey();
-
- // Fill vin
- BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
- wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
-
- // Sign
- int nIn = 0;
- BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*coin.first, wtxNew, nIn++))
- return false;
-
- // Limit size
- unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
- if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
- return false;
- dPriority /= nBytes;
-
- // Check that enough fee is included
- int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
- bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
- if (nFeeRet < max(nPayFee, nMinFee))
- {
- nFeeRet = max(nPayFee, nMinFee);
- continue;
- }
-
- // Fill vtxPrev by copying from previous transactions vtxPrev
- wtxNew.AddSupportingTransactions(txdb);
- wtxNew.fTimeReceivedIsTxTime = true;
-
- break;
- }
- }
+ fGenerateBitcoins = fGenerate;
+ WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
+ MainFrameRepaint();
}
- return true;
-}
-
-bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
-{
- vector< pair<CScript, int64> > vecSend;
- vecSend.push_back(make_pair(scriptPubKey, nValue));
- return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
-}
-
-// Call after CreateTransaction unless you want to abort
-bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
-{
- CRITICAL_BLOCK(cs_main)
+ if (fGenerateBitcoins)
{
- printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
- CRITICAL_BLOCK(cs_mapWallet)
- {
- // This is only to keep the database open to defeat the auto-flush for the
- // duration of this scope. This is the only place where this optimization
- // maybe makes sense; please don't do it anywhere else.
- CWalletDB walletdb("r");
-
- // Take key pair from key pool so it won't be used again
- reservekey.KeepKey();
-
- // Add tx to wallet, because if it has change it's also ours,
- // otherwise just for transaction history.
- AddToWallet(wtxNew);
-
- // Mark old coins as spent
- set<CWalletTx*> setCoins;
- BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
- {
- CWalletTx &pcoin = mapWallet[txin.prevout.hash];
- pcoin.MarkSpent(txin.prevout.n);
- pcoin.WriteToDisk();
- vWalletUpdated.push_back(pcoin.GetHash());
- }
- }
-
- // Track how many getdata requests our transaction gets
- CRITICAL_BLOCK(cs_mapRequestCount)
- mapRequestCount[wtxNew.GetHash()] = 0;
-
- // Broadcast
- if (!wtxNew.AcceptToMemoryPool())
+ int nProcessors = boost::thread::hardware_concurrency();
+ printf("%d processors\n", nProcessors);
+ if (nProcessors < 1)
+ nProcessors = 1;
+ if (fLimitProcessors && nProcessors > nLimitProcessors)
+ nProcessors = nLimitProcessors;
+ int nAddThreads = nProcessors - vnThreadsRunning[3];
+ printf("Starting %d BitcoinMiner threads\n", nAddThreads);
+ for (int i = 0; i < nAddThreads; i++)
{
- // This must not fail. The transaction has already been signed and recorded.
- printf("CommitTransaction() : Error: Transaction not valid");
- return false;
+ if (!CreateThread(ThreadBitcoinMiner, pwallet))
+ printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
+ Sleep(10);
}
- wtxNew.RelayWalletTransaction();
- }
- MainFrameRepaint();
- return true;
-}
-
-
-
-
-// requires cs_main lock
-string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
-{
- CReserveKey reservekey;
- int64 nFeeRequired;
- if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
- {
- string strError;
- if (nValue + nFeeRequired > GetBalance())
- strError = strprintf(_("Error: 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
- strError = _("Error: Transaction creation failed ");
- printf("SendMoney() : %s", strError.c_str());
- return strError;
}
-
- if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
- return "ABORTED";
-
- if (!CommitTransaction(wtxNew, reservekey))
- return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
-
- MainFrameRepaint();
- return "";
-}
-
-
-
-// requires cs_main lock
-string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
-{
- // Check amount
- if (nValue <= 0)
- return _("Invalid amount");
- if (nValue + nTransactionFee > GetBalance())
- return _("Insufficient funds");
-
- // Parse bitcoin address
- CScript scriptPubKey;
- if (!scriptPubKey.SetBitcoinAddress(strAddress))
- return _("Invalid bitcoin address");
-
- return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
}
diff --git a/src/main.h b/src/main.h
index 73935bcee2..aa74ac5ab3 100644
--- a/src/main.h
+++ b/src/main.h
@@ -7,22 +7,18 @@
#include "bignum.h"
#include "net.h"
#include "key.h"
-#include "db.h"
#include "script.h"
+#include "db.h"
#include <list>
-class COutPoint;
-class CInPoint;
-class CDiskTxPos;
-class CCoinBase;
-class CTxIn;
-class CTxOut;
-class CTransaction;
class CBlock;
class CBlockIndex;
class CWalletTx;
+class CWallet;
class CKeyItem;
+class CReserveKey;
+class CWalletDB;
class CMessageHeader;
class CAddress;
@@ -63,13 +59,11 @@ extern CBigNum bnBestInvalidWork;
extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
-extern std::map<uint256, int> mapRequestCount;
-extern CCriticalSection cs_mapRequestCount;
-extern std::map<std::string, std::string> mapAddressBook;
-extern CCriticalSection cs_mapAddressBook;
-extern std::vector<unsigned char> vchDefaultKey;
extern double dHashesPerSec;
extern int64 nHPSTimerStart;
+extern int64 nTimeBestReceived;
+extern CCriticalSection cs_setpwalletRegistered;
+extern std::set<CWallet*> setpwalletRegistered;
// Settings
extern int fGenerateBitcoins;
@@ -89,34 +83,20 @@ class CReserveKey;
class CTxDB;
class CTxIndex;
+void RegisterWallet(CWallet* pwalletIn);
+void UnregisterWallet(CWallet* pwalletIn);
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet);
-bool AddKey(const CKey& key);
-std::vector<unsigned char> GenerateNewKey();
-bool AddToWallet(const CWalletTx& wtxIn);
-void WalletUpdateSpent(const COutPoint& prevout);
-int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
-void ReacceptWalletTransactions();
bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
bool ProcessMessages(CNode* pfrom);
-bool ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vRecv);
bool SendMessages(CNode* pto, bool fSendTrickle);
-int64 GetBalance();
-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 GenerateBitcoins(bool fGenerate);
-void ThreadBitcoinMiner(void* parg);
+void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
CBlock* CreateNewBlock(CReserveKey& reservekey);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
-bool CheckWork(CBlock* pblock, CReserveKey& reservekey);
-void BitcoinMiner();
+bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
int GetTotalBlocksEstimate();
bool IsInitialBlockDownload();
@@ -133,6 +113,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
{
public:
@@ -315,9 +312,6 @@ public:
{
printf("%s\n", ToString().c_str());
}
-
- bool IsMine() const;
- int64 GetDebit() const;
};
@@ -366,36 +360,6 @@ public:
return SerializeHash(*this);
}
- bool IsMine() const
- {
- return ::IsMine(scriptPubKey);
- }
-
- int64 GetCredit() const
- {
- if (!MoneyRange(nValue))
- throw std::runtime_error("CTxOut::GetCredit() : value out of range");
- return (IsMine() ? nValue : 0);
- }
-
- bool IsChange() const
- {
- // On a debit transaction, a txout that's mine but isn't in the address book is change
- std::vector<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)
{
return (a.nValue == b.nValue &&
@@ -540,57 +504,6 @@ public:
return true;
}
- bool IsMine() const
- {
- BOOST_FOREACH(const CTxOut& txout, vout)
- if (txout.IsMine())
- return true;
- return false;
- }
-
- bool IsFromMe() const
- {
- return (GetDebit() > 0);
- }
-
- int64 GetDebit() const
- {
- int64 nDebit = 0;
- BOOST_FOREACH(const CTxIn& txin, vin)
- {
- nDebit += txin.GetDebit();
- if (!MoneyRange(nDebit))
- throw std::runtime_error("CTransaction::GetDebit() : value out of range");
- }
- return nDebit;
- }
-
- int64 GetCredit() const
- {
- int64 nCredit = 0;
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- nCredit += txout.GetCredit();
- if (!MoneyRange(nCredit))
- throw std::runtime_error("CTransaction::GetCredit() : value out of range");
- }
- return nCredit;
- }
-
- int64 GetChange() const
- {
- if (IsCoinBase())
- return 0;
- int64 nChange = 0;
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- nChange += txout.GetChange();
- if (!MoneyRange(nChange))
- throw std::runtime_error("CTransaction::GetChange() : value out of range");
- }
- return nChange;
- }
-
int64 GetValueOut() const
{
int64 nValueOut = 0;
@@ -722,11 +635,7 @@ public:
bool ClientConnectInputs();
bool CheckTransaction() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
- bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL)
- {
- CTxDB txdb("r");
- return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
- }
+ bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
protected:
bool AddToMemoryPoolUnchecked();
public:
@@ -785,307 +694,7 @@ public:
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
int GetBlocksToMaturity() const;
bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true);
- bool AcceptToMemoryPool() { CTxDB txdb("r"); return AcceptToMemoryPool(txdb); }
-};
-
-
-
-
-//
-// A transaction with a bunch of additional info that only the owner cares
-// about. It includes any unrecorded transactions needed to link it back
-// to the block chain.
-//
-class CWalletTx : public CMerkleTx
-{
-public:
- std::vector<CMerkleTx> vtxPrev;
- std::map<std::string, std::string> mapValue;
- std::vector<std::pair<std::string, std::string> > vOrderForm;
- unsigned int fTimeReceivedIsTxTime;
- unsigned int nTimeReceived; // time received by this node
- char fFromMe;
- std::string strFromAccount;
- std::vector<char> vfSpent;
-
- // memory only
- mutable char fDebitCached;
- mutable char fCreditCached;
- mutable char fAvailableCreditCached;
- mutable char fChangeCached;
- mutable int64 nDebitCached;
- mutable int64 nCreditCached;
- mutable int64 nAvailableCreditCached;
- mutable int64 nChangeCached;
-
- // memory only UI hints
- mutable unsigned int nTimeDisplayed;
- mutable int nLinesDisplayed;
- mutable char fConfirmedDisplayed;
-
-
- CWalletTx()
- {
- Init();
- }
-
- CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn)
- {
- Init();
- }
-
- CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn)
- {
- Init();
- }
-
- void Init()
- {
- vtxPrev.clear();
- mapValue.clear();
- vOrderForm.clear();
- fTimeReceivedIsTxTime = false;
- nTimeReceived = 0;
- fFromMe = false;
- strFromAccount.clear();
- vfSpent.clear();
- fDebitCached = false;
- fCreditCached = false;
- fAvailableCreditCached = false;
- fChangeCached = false;
- nDebitCached = 0;
- nCreditCached = 0;
- nAvailableCreditCached = 0;
- nChangeCached = 0;
- nTimeDisplayed = 0;
- nLinesDisplayed = 0;
- fConfirmedDisplayed = false;
- }
-
- IMPLEMENT_SERIALIZE
- (
- CWalletTx* pthis = const_cast<CWalletTx*>(this);
- if (fRead)
- pthis->Init();
- char fSpent = false;
-
- if (!fRead)
- {
- pthis->mapValue["fromaccount"] = pthis->strFromAccount;
-
- std::string str;
- BOOST_FOREACH(char f, vfSpent)
- {
- str += (f ? '1' : '0');
- if (f)
- fSpent = true;
- }
- pthis->mapValue["spent"] = str;
- }
-
- nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
- READWRITE(vtxPrev);
- READWRITE(mapValue);
- READWRITE(vOrderForm);
- READWRITE(fTimeReceivedIsTxTime);
- READWRITE(nTimeReceived);
- READWRITE(fFromMe);
- READWRITE(fSpent);
-
- if (fRead)
- {
- pthis->strFromAccount = pthis->mapValue["fromaccount"];
-
- if (mapValue.count("spent"))
- BOOST_FOREACH(char c, pthis->mapValue["spent"])
- pthis->vfSpent.push_back(c != '0');
- else
- pthis->vfSpent.assign(vout.size(), fSpent);
- }
-
- pthis->mapValue.erase("fromaccount");
- pthis->mapValue.erase("version");
- pthis->mapValue.erase("spent");
- )
-
- // marks certain txout's as spent
- // returns true if any update took place
- bool UpdateSpent(const std::vector<char>& vfNewSpent)
- {
- bool fReturn = false;
- for (int i=0; i < vfNewSpent.size(); i++)
- {
- if (i == vfSpent.size())
- break;
-
- if (vfNewSpent[i] && !vfSpent[i])
- {
- vfSpent[i] = true;
- fReturn = true;
- fAvailableCreditCached = false;
- }
- }
- return fReturn;
- }
-
- void MarkDirty()
- {
- fCreditCached = false;
- fAvailableCreditCached = false;
- fDebitCached = false;
- fChangeCached = false;
- }
-
- void MarkSpent(unsigned int nOut)
- {
- if (nOut >= vout.size())
- throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
- vfSpent.resize(vout.size());
- if (!vfSpent[nOut])
- {
- vfSpent[nOut] = true;
- fAvailableCreditCached = false;
- }
- }
-
- bool IsSpent(unsigned int nOut) const
- {
- if (nOut >= vout.size())
- throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
- if (nOut >= vfSpent.size())
- return false;
- return (!!vfSpent[nOut]);
- }
-
- int64 GetDebit() const
- {
- if (vin.empty())
- return 0;
- if (fDebitCached)
- return nDebitCached;
- nDebitCached = CTransaction::GetDebit();
- fDebitCached = true;
- return nDebitCached;
- }
-
- int64 GetCredit(bool fUseCache=true) const
- {
- // Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsCoinBase() && GetBlocksToMaturity() > 0)
- return 0;
-
- // GetBalance can assume transactions in mapWallet won't change
- if (fUseCache && fCreditCached)
- return nCreditCached;
- nCreditCached = CTransaction::GetCredit();
- fCreditCached = true;
- return nCreditCached;
- }
-
- int64 GetAvailableCredit(bool fUseCache=true) const
- {
- // Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsCoinBase() && GetBlocksToMaturity() > 0)
- return 0;
-
- if (fUseCache && fAvailableCreditCached)
- return nAvailableCreditCached;
-
- int64 nCredit = 0;
- for (int i = 0; i < vout.size(); i++)
- {
- if (!IsSpent(i))
- {
- const CTxOut &txout = vout[i];
- nCredit += txout.GetCredit();
- if (!MoneyRange(nCredit))
- throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
- }
- }
-
- nAvailableCreditCached = nCredit;
- fAvailableCreditCached = true;
- return nCredit;
- }
-
-
- int64 GetChange() const
- {
- if (fChangeCached)
- return nChangeCached;
- nChangeCached = CTransaction::GetChange();
- fChangeCached = true;
- return nChangeCached;
- }
-
- 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;
-
- void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived,
- int64& nSent, int64& nFee) const;
-
- bool IsFromMe() const
- {
- return (GetDebit() > 0);
- }
-
- bool IsConfirmed() const
- {
- // Quick answer in most cases
- if (!IsFinal())
- return false;
- if (GetDepthInMainChain() >= 1)
- return true;
- if (!IsFromMe()) // using wtx's cached debit
- return false;
-
- // If no confirmations but it's from us, we can still
- // consider it confirmed if all dependencies are confirmed
- std::map<uint256, const CMerkleTx*> mapPrev;
- std::vector<const CMerkleTx*> vWorkQueue;
- vWorkQueue.reserve(vtxPrev.size()+1);
- vWorkQueue.push_back(this);
- for (int i = 0; i < vWorkQueue.size(); i++)
- {
- const CMerkleTx* ptx = vWorkQueue[i];
-
- if (!ptx->IsFinal())
- return false;
- if (ptx->GetDepthInMainChain() >= 1)
- continue;
- if (!ptx->IsFromMe())
- return false;
-
- if (mapPrev.empty())
- BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
- mapPrev[tx.GetHash()] = &tx;
-
- BOOST_FOREACH(const CTxIn& txin, ptx->vin)
- {
- if (!mapPrev.count(txin.prevout.hash))
- return false;
- vWorkQueue.push_back(mapPrev[txin.prevout.hash]);
- }
- }
- return true;
- }
-
- bool WriteToDisk()
- {
- return CWalletDB().WriteTx(GetHash(), *this);
- }
-
-
- int64 GetTxTime() const;
- int GetRequestCount() const;
-
- void AddSupportingTransactions(CTxDB& txdb);
-
- bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
- bool AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); }
-
- void RelayWalletTransaction(CTxDB& txdb);
- void RelayWalletTransaction() { CTxDB txdb("r"); RelayWalletTransaction(txdb); }
+ bool AcceptToMemoryPool();
};
@@ -1745,114 +1354,6 @@ public:
-//
-// Private key that includes an expiration date in case it never gets used.
-//
-class CWalletKey
-{
-public:
- CPrivKey vchPrivKey;
- int64 nTimeCreated;
- int64 nTimeExpires;
- std::string strComment;
- //// todo: add something to note what created it (user, getnewaddress, change)
- //// maybe should have a map<string, string> property map
-
- CWalletKey(int64 nExpires=0)
- {
- nTimeCreated = (nExpires ? GetTime() : 0);
- nTimeExpires = nExpires;
- }
-
- IMPLEMENT_SERIALIZE
- (
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- READWRITE(vchPrivKey);
- READWRITE(nTimeCreated);
- READWRITE(nTimeExpires);
- READWRITE(strComment);
- )
-};
-
-
-
-
-
-
-//
-// Account information.
-// Stored in wallet with key "acc"+string account name
-//
-class CAccount
-{
-public:
- std::vector<unsigned char> vchPubKey;
-
- CAccount()
- {
- SetNull();
- }
-
- void SetNull()
- {
- vchPubKey.clear();
- }
-
- IMPLEMENT_SERIALIZE
- (
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- READWRITE(vchPubKey);
- )
-};
-
-
-
-//
-// Internal transfers.
-// Database key is acentry<account><counter>
-//
-class CAccountingEntry
-{
-public:
- std::string strAccount;
- int64 nCreditDebit;
- int64 nTime;
- std::string strOtherAccount;
- std::string strComment;
-
- CAccountingEntry()
- {
- SetNull();
- }
-
- void SetNull()
- {
- nCreditDebit = 0;
- nTime = 0;
- strAccount.clear();
- strOtherAccount.clear();
- strComment.clear();
- }
-
- IMPLEMENT_SERIALIZE
- (
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- // Note: strAccount is serialized as part of the key, not here.
- READWRITE(nCreditDebit);
- READWRITE(nTime);
- READWRITE(strOtherAccount);
- READWRITE(strComment);
- )
-};
-
-
-
-
-
-
@@ -2064,13 +1565,9 @@ public:
+
extern std::map<uint256, CTransaction> mapTransactions;
-extern std::map<uint256, CWalletTx> mapWallet;
-extern std::vector<uint256> vWalletUpdated;
-extern CCriticalSection cs_mapWallet;
-extern std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
extern std::map<uint160, std::vector<unsigned char> > mapPubKeys;
-extern CCriticalSection cs_mapKeys;
-extern CKey keyUser;
+extern CCriticalSection cs_mapPubKeys;
#endif
diff --git a/src/net.cpp b/src/net.cpp
index 8b439efdca..4b13726230 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1117,7 +1117,7 @@ void MapPort(bool fMapPort)
if (fUseUPnP != fMapPort)
{
fUseUPnP = fMapPort;
- CWalletDB().WriteSetting("fUseUPnP", fUseUPnP);
+ WriteSetting("fUseUPnP", fUseUPnP);
}
if (fUseUPnP && vnThreadsRunning[5] < 1)
{
@@ -1698,7 +1698,7 @@ void StartNode(void* parg)
printf("Error: CreateThread(ThreadMessageHandler) failed\n");
// Generate coins in the background
- GenerateBitcoins(fGenerateBitcoins);
+ GenerateBitcoins(fGenerateBitcoins, pwalletMain);
}
bool StopNode()
diff --git a/src/noui.h b/src/noui.h
index afb19526c1..d0072df7f2 100644
--- a/src/noui.h
+++ b/src/noui.h
@@ -5,6 +5,8 @@
#define BITCOIN_NOUI_H
#include <string>
+#include <boost/function.hpp>
+#include "wallet.h"
typedef void wxWindow;
#define wxYES 0x00000002
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 1cd82b7626..eece092f0d 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -1,6 +1,7 @@
#include "addresstablemodel.h"
#include "guiutil.h"
-#include "main.h"
+
+#include "headers.h"
#include <QFont>
#include <QColor>
@@ -22,31 +23,25 @@ struct AddressTableEntry
AddressTableEntry() {}
AddressTableEntry(Type type, const QString &label, const QString &address):
type(type), label(label), address(address) {}
-
- bool isDefaultAddress() const
- {
- std::vector<unsigned char> vchPubKey;
- if (CWalletDB("r").ReadDefaultKey(vchPubKey))
- {
- return address == QString::fromStdString(PubKeyToAddress(vchPubKey));
- }
- return false;
- }
};
// Private implementation
struct AddressTablePriv
{
+ CWallet *wallet;
QList<AddressTableEntry> cachedAddressTable;
+ AddressTablePriv(CWallet *wallet):
+ wallet(wallet) {}
+
void refreshAddressTable()
{
cachedAddressTable.clear();
- CRITICAL_BLOCK(cs_mapKeys)
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(wallet->cs_mapKeys)
+ CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{
- BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wallet->mapAddressBook)
{
std::string strAddress = item.first;
std::string strName = item.second;
@@ -75,13 +70,18 @@ struct AddressTablePriv
return 0;
}
}
+
+ bool isDefaultAddress(const AddressTableEntry *rec)
+ {
+ return rec->address == QString::fromStdString(wallet->GetDefaultAddress());
+ }
};
-AddressTableModel::AddressTableModel(QObject *parent) :
- QAbstractTableModel(parent),priv(0)
+AddressTableModel::AddressTableModel(CWallet *wallet, QObject *parent) :
+ QAbstractTableModel(parent),wallet(wallet),priv(0)
{
columns << tr("Label") << tr("Address");
- priv = new AddressTablePriv();
+ priv = new AddressTablePriv(wallet);
priv->refreshAddressTable();
}
@@ -118,7 +118,7 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
case Address:
return rec->address;
case IsDefaultAddress:
- return rec->isDefaultAddress();
+ return priv->isDefaultAddress(rec);
}
}
else if (role == Qt::FontRole)
@@ -128,7 +128,7 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
{
font = GUIUtil::bitcoinAddressFont();
}
- if(rec->isDefaultAddress())
+ if(priv->isDefaultAddress(rec))
{
font.setBold(true);
}
@@ -137,14 +137,14 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
else if (role == Qt::ForegroundRole)
{
// Show default address in alternative color
- if(rec->isDefaultAddress())
+ if(priv->isDefaultAddress(rec))
{
return QColor(0,0,255);
}
}
else if (role == Qt::ToolTipRole)
{
- if(rec->isDefaultAddress())
+ if(priv->isDefaultAddress(rec))
{
return tr("Default receiving address");
}
@@ -174,7 +174,7 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
switch(index.column())
{
case Label:
- SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
+ wallet->SetAddressBookName(rec->address.toStdString(), value.toString().toStdString());
rec->label = value.toString();
break;
case Address:
@@ -182,9 +182,9 @@ bool AddressTableModel::setData(const QModelIndex & index, const QVariant & valu
if(rec->type == AddressTableEntry::Sending)
{
// Remove old entry
- CWalletDB().EraseName(rec->address.toStdString());
+ wallet->EraseAddressBookName(rec->address.toStdString());
// Add new entry with new address
- SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
+ wallet->SetAddressBookName(value.toString().toStdString(), rec->label.toStdString());
rec->address = value.toString();
}
@@ -245,9 +245,9 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
if(type == Send)
{
// Check for duplicate
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{
- if(mapAddressBook.count(strAddress))
+ if(wallet->mapAddressBook.count(strAddress))
{
return QString();
}
@@ -257,7 +257,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
{
// Generate a new address to associate with given label, optionally
// set as default receiving address.
- strAddress = PubKeyToAddress(GetKeyFromKeyPool());
+ strAddress = PubKeyToAddress(wallet->GetKeyFromKeyPool());
if(setAsDefault)
{
setDefaultAddress(QString::fromStdString(strAddress));
@@ -268,7 +268,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
// Add entry and update list
- SetAddressBookName(strAddress, strLabel);
+ wallet->SetAddressBookName(strAddress, strLabel);
updateList();
return QString::fromStdString(strAddress);
}
@@ -283,33 +283,19 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex & paren
// Also refuse to remove receiving addresses.
return false;
}
- CWalletDB().EraseName(rec->address.toStdString());
+ wallet->EraseAddressBookName(rec->address.toStdString());
updateList();
return true;
}
QString AddressTableModel::getDefaultAddress() const
{
- std::vector<unsigned char> vchPubKey;
- if (CWalletDB("r").ReadDefaultKey(vchPubKey))
- {
- return QString::fromStdString(PubKeyToAddress(vchPubKey));
- }
- else
- {
- return QString();
- }
+ return QString::fromStdString(wallet->GetDefaultAddress());
}
void AddressTableModel::setDefaultAddress(const QString &defaultAddress)
{
- uint160 hash160;
- std::string strAddress = defaultAddress.toStdString();
- if (!AddressToHash160(strAddress, hash160))
- return;
- if (!mapPubKeys.count(hash160))
- return;
- CWalletDB().WriteDefaultKey(mapPubKeys[hash160]);
+ wallet->SetDefaultAddress(defaultAddress.toStdString());
}
void AddressTableModel::update()
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 32dd4d9f1d..d8465853b2 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -5,12 +5,13 @@
#include <QStringList>
class AddressTablePriv;
+class CWallet;
class AddressTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
- explicit AddressTableModel(QObject *parent = 0);
+ explicit AddressTableModel(CWallet *wallet, QObject *parent = 0);
~AddressTableModel();
enum ColumnIndex {
@@ -49,6 +50,7 @@ public:
void updateList();
private:
+ CWallet *wallet;
AddressTablePriv *priv;
QStringList columns;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 7d5712f4aa..c31be1b606 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -3,10 +3,9 @@
*/
#include "bitcoingui.h"
#include "clientmodel.h"
-#include "util.h"
+
+#include "headers.h"
#include "init.h"
-#include "main.h"
-#include "qtui.h"
#include <QApplication>
#include <QMessageBox>
@@ -114,7 +113,7 @@ int main(int argc, char *argv[])
if(AppInit2(argc, argv))
{
BitcoinGUI window;
- ClientModel model;
+ ClientModel model(pwalletMain);
guiref = &window;
window.setModel(&model);
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 1b4e13c420..76ae3ddb3f 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -16,7 +16,7 @@
#include "transactiondescdialog.h"
#include "addresstablemodel.h"
-#include "main.h"
+#include "headers.h"
#include <QApplication>
#include <QMainWindow>
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index e39bb7ecb1..b70b71ee4f 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -1,14 +1,15 @@
#include "clientmodel.h"
-#include "main.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "addresstablemodel.h"
#include "transactiontablemodel.h"
+#include "headers.h"
+
#include <QTimer>
-ClientModel::ClientModel(QObject *parent) :
- QObject(parent), optionsModel(0), addressTableModel(0),
+ClientModel::ClientModel(CWallet *wallet, QObject *parent) :
+ QObject(parent), wallet(wallet), optionsModel(0), addressTableModel(0),
transactionTableModel(0)
{
// Until signal notifications is built into the bitcoin core,
@@ -17,14 +18,14 @@ ClientModel::ClientModel(QObject *parent) :
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(MODEL_UPDATE_DELAY);
- optionsModel = new OptionsModel(this);
- addressTableModel = new AddressTableModel(this);
- transactionTableModel = new TransactionTableModel(this);
+ optionsModel = new OptionsModel(wallet, this);
+ addressTableModel = new AddressTableModel(wallet, this);
+ transactionTableModel = new TransactionTableModel(wallet, this);
}
qint64 ClientModel::getBalance() const
{
- return GetBalance();
+ return wallet->GetBalance();
}
int ClientModel::getNumConnections() const
@@ -40,9 +41,9 @@ int ClientModel::getNumBlocks() const
int ClientModel::getNumTransactions() const
{
int numTransactions = 0;
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(wallet->cs_mapWallet)
{
- numTransactions = mapWallet.size();
+ numTransactions = wallet->mapWallet.size();
}
return numTransactions;
}
@@ -92,7 +93,7 @@ ClientModel::StatusCode ClientModel::sendCoins(const QString &payTo, qint64 payA
CScript scriptPubKey;
scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
- std::string strError = SendMoney(scriptPubKey, payAmount, wtx, true);
+ std::string strError = wallet->SendMoney(scriptPubKey, payAmount, wtx, true);
if (strError == "")
{
// OK
@@ -110,9 +111,11 @@ ClientModel::StatusCode ClientModel::sendCoins(const QString &payTo, qint64 payA
// Add addresses that we've sent to to the address book
std::string strAddress = payTo.toStdString();
- CRITICAL_BLOCK(cs_mapAddressBook)
- if (!mapAddressBook.count(strAddress))
- SetAddressBookName(strAddress, addToAddressBookAs.toStdString());
+ CRITICAL_BLOCK(wallet->cs_mapAddressBook)
+ {
+ if (!wallet->mapAddressBook.count(strAddress))
+ wallet->SetAddressBookName(strAddress, addToAddressBookAs.toStdString());
+ }
return OK;
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index da3e52e20e..9c23a14a0a 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -6,12 +6,13 @@
class OptionsModel;
class AddressTableModel;
class TransactionTableModel;
+class CWallet;
class ClientModel : public QObject
{
Q_OBJECT
public:
- explicit ClientModel(QObject *parent = 0);
+ explicit ClientModel(CWallet *wallet, QObject *parent = 0);
enum StatusCode
{
@@ -41,6 +42,8 @@ public:
/* Send coins */
StatusCode sendCoins(const QString &payTo, qint64 payAmount, const QString &addToAddressBookAs=QString());
private:
+ CWallet *wallet;
+
OptionsModel *optionsModel;
AddressTableModel *addressTableModel;
TransactionTableModel *transactionTableModel;
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 3788f9fd7c..8f285c6446 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -1,11 +1,12 @@
#include "optionsmodel.h"
-#include "main.h"
-#include "net.h"
+
+#include "headers.h"
#include <QDebug>
-OptionsModel::OptionsModel(QObject *parent) :
- QAbstractListModel(parent)
+OptionsModel::OptionsModel(CWallet *wallet, QObject *parent) :
+ QAbstractListModel(parent),
+ wallet(wallet)
{
}
@@ -48,7 +49,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
bool successful = true; /* set to false on parse error */
if(role == Qt::EditRole)
{
- CWalletDB walletdb;
+ CWalletDB walletdb(wallet->strWalletFile);
switch(index.row())
{
case StartAtStartup:
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 0124e2ab47..bdb797a2de 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -3,6 +3,8 @@
#include <QAbstractListModel>
+class CWallet;
+
/* Interface from QT to configuration data structure for bitcoin client.
To QT, the options are presented as a list with the different options
laid out vertically.
@@ -13,7 +15,7 @@ class OptionsModel : public QAbstractListModel
{
Q_OBJECT
public:
- explicit OptionsModel(QObject *parent = 0);
+ explicit OptionsModel(CWallet *wallet, QObject *parent = 0);
enum OptionID {
StartAtStartup,
@@ -35,6 +37,9 @@ public:
qint64 getTransactionFee();
bool getMinimizeToTray();
bool getMinimizeOnClose();
+private:
+ // Wallet stores persistent options
+ CWallet *wallet;
signals:
public slots:
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 84b617b7c4..bb2537a479 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -70,10 +70,10 @@ static string FormatTxStatus(const CWalletTx& wtx)
}
}
-string TransactionDesc::toHTML(CWalletTx &wtx)
+string TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
string strHTML;
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{
strHTML.reserve(4000);
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
@@ -122,19 +122,19 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
// Credit
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- if (txout.IsMine())
+ if (wallet->IsMine(txout))
{
vector<unsigned char> vchPubKey;
- if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
+ if (ExtractPubKey(txout.scriptPubKey, wallet, vchPubKey))
{
string strAddress = PubKeyToAddress(vchPubKey);
- if (mapAddressBook.count(strAddress))
+ if (wallet->mapAddressBook.count(strAddress))
{
strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
strHTML += _("<b>To:</b> ");
strHTML += HtmlEscape(strAddress);
- if (!mapAddressBook[strAddress].empty())
- strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
+ if (!wallet->mapAddressBook[strAddress].empty())
+ strHTML += _(" (yours, label: ") + wallet->mapAddressBook[strAddress] + ")";
else
strHTML += _(" (yours)");
strHTML += "<br>";
@@ -156,8 +156,8 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
// Online transaction
strAddress = wtx.mapValue["to"];
strHTML += _("<b>To:</b> ");
- if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
- strHTML += mapAddressBook[strAddress] + " ";
+ if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty())
+ strHTML += wallet->mapAddressBook[strAddress] + " ";
strHTML += HtmlEscape(strAddress) + "<br>";
}
@@ -172,7 +172,7 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
//
int64 nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- nUnmatured += txout.GetCredit();
+ nUnmatured += wallet->GetCredit(txout);
strHTML += _("<b>Credit:</b> ");
if (wtx.IsInMainChain())
strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
@@ -191,11 +191,11 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
{
bool fAllFromMe = true;
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllFromMe = fAllFromMe && txin.IsMine();
+ fAllFromMe = fAllFromMe && wallet->IsMine(txin);
bool fAllToMe = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllToMe = fAllToMe && txout.IsMine();
+ fAllToMe = fAllToMe && wallet->IsMine(txout);
if (fAllFromMe)
{
@@ -204,7 +204,7 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
//
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- if (txout.IsMine())
+ if (wallet->IsMine(txout))
continue;
if (wtx.mapValue["to"].empty())
@@ -215,8 +215,8 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
{
string strAddress = Hash160ToAddress(hash160);
strHTML += _("<b>To:</b> ");
- if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
- strHTML += mapAddressBook[strAddress] + " ";
+ if (wallet->mapAddressBook.count(strAddress) && !wallet->mapAddressBook[strAddress].empty())
+ strHTML += wallet->mapAddressBook[strAddress] + " ";
strHTML += strAddress;
strHTML += "<br>";
}
@@ -244,11 +244,11 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
// Mixed debit transaction
//
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- if (txin.IsMine())
- strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
+ if (wallet->IsMine(txin))
+ strHTML += _("<b>Debit:</b> ") + FormatMoney(-wallet->GetDebit(txin)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- if (txout.IsMine())
- strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
+ if (wallet->IsMine(txout))
+ strHTML += _("<b>Credit:</b> ") + FormatMoney(wallet->GetCredit(txout)) + "<br>";
}
}
@@ -274,30 +274,30 @@ string TransactionDesc::toHTML(CWalletTx &wtx)
{
strHTML += "<hr><br>debug print<br><br>";
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- if (txin.IsMine())
- strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
+ if(wallet->IsMine(txin))
+ strHTML += "<b>Debit:</b> " + FormatMoney(-wallet->IsMine(txin)) + "<br>";
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- if (txout.IsMine())
- strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
+ if(wallet->IsMine(txout))
+ strHTML += "<b>Credit:</b> " + FormatMoney(wallet->IsMine(txout)) + "<br>";
strHTML += "<br><b>Transaction:</b><br>";
strHTML += HtmlEscape(wtx.ToString(), true);
strHTML += "<br><b>Inputs:</b><br>";
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(wallet->cs_mapWallet)
{
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
COutPoint prevout = txin.prevout;
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
- if (mi != mapWallet.end())
+ map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(prevout.hash);
+ if (mi != wallet->mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (prevout.n < prev.vout.size())
{
strHTML += HtmlEscape(prev.ToString(), true);
strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
- strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
+ strHTML = strHTML + "IsMine=" + (wallet->IsMine(prev.vout[prevout.n]) ? "true" : "false") + "<br>";
}
}
}
diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h
index 5a85949341..fde861b6fb 100644
--- a/src/qt/transactiondesc.h
+++ b/src/qt/transactiondesc.h
@@ -3,13 +3,14 @@
#include <string>
+class CWallet;
class CWalletTx;
class TransactionDesc
{
public:
/* Provide human-readable extended HTML description of a transaction */
- static std::string toHTML(CWalletTx &wtx);
+ static std::string toHTML(CWallet *wallet, CWalletTx &wtx);
};
#endif // TRANSACTIONDESC_H
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 2f00fa8752..864dffa99e 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -1,5 +1,6 @@
#include "transactionrecord.h"
+#include "headers.h"
/* Return positive answer if transaction should be shown in list.
*/
@@ -29,7 +30,7 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx)
/*
* Decompose CWallet transaction to model transaction records.
*/
-QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx &wtx)
+QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
{
QList<TransactionRecord> parts;
int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
@@ -59,7 +60,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx
{
int64 nUnmatured = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- nUnmatured += txout.GetCredit();
+ nUnmatured += wallet->GetCredit(txout);
sub.credit = nUnmatured;
}
}
@@ -76,10 +77,10 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx
sub.type = TransactionRecord::RecvWithAddress;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- if (txout.IsMine())
+ if(wallet->IsMine(txout))
{
std::vector<unsigned char> vchPubKey;
- if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
+ if (ExtractPubKey(txout.scriptPubKey, wallet, vchPubKey))
{
sub.address = PubKeyToAddress(vchPubKey);
}
@@ -93,11 +94,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx
{
bool fAllFromMe = true;
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllFromMe = fAllFromMe && txin.IsMine();
+ fAllFromMe = fAllFromMe && wallet->IsMine(txin);
bool fAllToMe = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllToMe = fAllToMe && txout.IsMine();
+ fAllToMe = fAllToMe && wallet->IsMine(txout);
if (fAllFromMe && fAllToMe)
{
@@ -120,13 +121,13 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx
TransactionRecord sub(hash, nTime);
sub.idx = parts.size();
- if (txout.IsMine())
+ if(wallet->IsMine(txout))
{
// Ignore parts sent to self, as this is usually the change
// from a transaction sent back to our own address.
continue;
}
- else if (!mapValue["to"].empty())
+ else if(!mapValue["to"].empty())
{
// Sent to IP
sub.type = TransactionRecord::SendToIP;
@@ -160,9 +161,9 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWalletTx
//
bool fAllMine = true;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- fAllMine = fAllMine && txout.IsMine();
+ fAllMine = fAllMine && wallet->IsMine(txout);
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
- fAllMine = fAllMine && txin.IsMine();
+ fAllMine = fAllMine && wallet->IsMine(txin);
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
}
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index a7f6537b3f..ba071dfdc9 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -5,6 +5,8 @@
#include <QList>
+class CWallet;
+
class TransactionStatus
{
public:
@@ -84,7 +86,7 @@ public:
/* Decompose CWallet transaction to model transaction records.
*/
static bool showTransaction(const CWalletTx &wtx);
- static QList<TransactionRecord> decomposeTransaction(const CWalletTx &wtx);
+ static QList<TransactionRecord> decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx);
/* Fixed */
uint256 hash;
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index dc3ef245e0..18ab421e3c 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -2,9 +2,10 @@
#include "guiutil.h"
#include "transactionrecord.h"
#include "guiconstants.h"
-#include "main.h"
#include "transactiondesc.h"
+#include "headers.h"
+
#include <QLocale>
#include <QDebug>
#include <QList>
@@ -37,11 +38,12 @@ struct TxLessThan
// Private implementation
struct TransactionTablePriv
{
- TransactionTablePriv(TransactionTableModel *parent):
+ TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent):
+ wallet(wallet),
parent(parent)
{
}
-
+ CWallet *wallet;
TransactionTableModel *parent;
/* Local cache of wallet.
@@ -58,11 +60,11 @@ struct TransactionTablePriv
qDebug() << "refreshWallet";
#endif
cachedWallet.clear();
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(wallet->cs_mapWallet)
{
- for(std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
{
- cachedWallet.append(TransactionRecord::decomposeTransaction(it->second));
+ cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
}
}
}
@@ -84,14 +86,14 @@ struct TransactionTablePriv
QList<uint256> updated_sorted = updated;
qSort(updated_sorted);
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(wallet->cs_mapWallet)
{
for(int update_idx = updated_sorted.size()-1; update_idx >= 0; --update_idx)
{
const uint256 &hash = updated_sorted.at(update_idx);
/* Find transaction in wallet */
- std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
- bool inWallet = mi != mapWallet.end();
+ std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
+ bool inWallet = mi != wallet->mapWallet.end();
/* Find bounds of this transaction in model */
QList<TransactionRecord>::iterator lower = qLowerBound(
cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
@@ -100,6 +102,7 @@ struct TransactionTablePriv
int lowerIndex = (lower - cachedWallet.begin());
int upperIndex = (upper - cachedWallet.begin());
+ // Determine if transaction is in model already
bool inModel = false;
if(lower != upper)
{
@@ -115,7 +118,7 @@ struct TransactionTablePriv
{
// Added -- insert at the right position
QList<TransactionRecord> toInsert =
- TransactionRecord::decomposeTransaction(mi->second);
+ TransactionRecord::decomposeTransaction(wallet, mi->second);
if(!toInsert.isEmpty()) /* only if something to insert */
{
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
@@ -159,11 +162,11 @@ struct TransactionTablePriv
// simply re-use the cached status.
if(rec->statusUpdateNeeded())
{
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(wallet->cs_mapWallet)
{
- std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(rec->hash);
+ std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
- if(mi != mapWallet.end())
+ if(mi != wallet->mapWallet.end())
{
rec->updateStatus(mi->second);
}
@@ -179,12 +182,12 @@ struct TransactionTablePriv
QString describe(TransactionRecord *rec)
{
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(wallet->cs_mapWallet)
{
- std::map<uint256, CWalletTx>::iterator mi = mapWallet.find(rec->hash);
- if(mi != mapWallet.end())
+ std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
+ if(mi != wallet->mapWallet.end())
{
- return QString::fromStdString(TransactionDesc::toHTML(mi->second));
+ return QString::fromStdString(TransactionDesc::toHTML(wallet, mi->second));
}
}
return QString("");
@@ -202,9 +205,10 @@ static int column_alignments[] = {
Qt::AlignLeft|Qt::AlignVCenter
};
-TransactionTableModel::TransactionTableModel(QObject *parent):
+TransactionTableModel::TransactionTableModel(CWallet* wallet, QObject *parent):
QAbstractTableModel(parent),
- priv(new TransactionTablePriv(this))
+ wallet(wallet),
+ priv(new TransactionTablePriv(wallet, this))
{
columns << tr("Status") << tr("Date") << tr("Description") << tr("Debit") << tr("Credit");
@@ -225,15 +229,15 @@ void TransactionTableModel::update()
QList<uint256> updated;
// Check if there are changes to wallet map
- TRY_CRITICAL_BLOCK(cs_mapWallet)
+ TRY_CRITICAL_BLOCK(wallet->cs_mapWallet)
{
- if(!vWalletUpdated.empty())
+ if(!wallet->vWalletUpdated.empty())
{
- BOOST_FOREACH(uint256 hash, vWalletUpdated)
+ BOOST_FOREACH(uint256 hash, wallet->vWalletUpdated)
{
updated.append(hash);
}
- vWalletUpdated.clear();
+ wallet->vWalletUpdated.clear();
}
}
@@ -302,13 +306,13 @@ QVariant TransactionTableModel::formatTxDate(const TransactionRecord *wtx) const
address[0:12]... (label)
otherwise just return address
*/
-std::string lookupAddress(const std::string &address)
+std::string TransactionTableModel::lookupAddress(const std::string &address) const
{
std::string description;
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(wallet->cs_mapAddressBook)
{
- std::map<std::string, std::string>::iterator mi = mapAddressBook.find(address);
- if (mi != mapAddressBook.end() && !(*mi).second.empty())
+ std::map<std::string, std::string>::iterator mi = wallet->mapAddressBook.find(address);
+ if (mi != wallet->mapAddressBook.end() && !(*mi).second.empty())
{
std::string label = (*mi).second;
description += address.substr(0,12) + "... ";
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 804f004e38..72a645b3db 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -4,6 +4,7 @@
#include <QAbstractTableModel>
#include <QStringList>
+class CWallet;
class TransactionTablePriv;
class TransactionRecord;
@@ -11,7 +12,7 @@ class TransactionTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
- explicit TransactionTableModel(QObject *parent = 0);
+ explicit TransactionTableModel(CWallet* wallet, QObject *parent = 0);
~TransactionTableModel();
enum {
@@ -39,9 +40,11 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const;
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
private:
+ CWallet* wallet;
QStringList columns;
TransactionTablePriv *priv;
+ std::string lookupAddress(const std::string &address) const;
QVariant formatTxStatus(const TransactionRecord *wtx) const;
QVariant formatTxDate(const TransactionRecord *wtx) const;
QVariant formatTxDescription(const TransactionRecord *wtx) const;
diff --git a/src/qtui.h b/src/qtui.h
index 42f44e0d04..a3b9eb0148 100644
--- a/src/qtui.h
+++ b/src/qtui.h
@@ -6,6 +6,7 @@
#include <string>
#include <boost/function/function0.hpp>
+#include "wallet.h"
typedef void wxWindow;
#define wxYES 0x00000002
diff --git a/src/rpc.cpp b/src/rpc.cpp
index bc9b224518..644ad92297 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -14,6 +14,7 @@
#include <boost/algorithm/string.hpp>
#ifdef USE_SSL
#include <boost/asio/ssl.hpp>
+#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
#endif
@@ -264,14 +265,14 @@ Value setgenerate(const Array& params, bool fHelp)
{
int nGenProcLimit = params[1].get_int();
fLimitProcessors = (nGenProcLimit != -1);
- CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors);
+ WriteSetting("fLimitProcessors", fLimitProcessors);
if (nGenProcLimit != -1)
- CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
+ WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
if (nGenProcLimit == 0)
fGenerate = false;
}
- GenerateBitcoins(fGenerate);
+ GenerateBitcoins(fGenerate, pwalletMain);
return Value::null;
}
@@ -298,7 +299,7 @@ Value getinfo(const Array& params, bool fHelp)
Object obj;
obj.push_back(Pair("version", (int)VERSION));
- obj.push_back(Pair("balance", ValueFromAmount(GetBalance())));
+ obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
@@ -307,7 +308,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet));
- obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime()));
+ obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
@@ -329,9 +330,9 @@ Value getnewaddress(const Array& params, bool fHelp)
strAccount = AccountFromValue(params[0]);
// Generate a new key that is added to wallet
- string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
+ string strAddress = PubKeyToAddress(pwalletMain->GetKeyFromKeyPool());
- SetAddressBookName(strAddress, strAccount);
+ pwalletMain->SetAddressBookName(strAddress, strAccount);
return strAddress;
}
@@ -341,7 +342,7 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
{
string strAddress;
- CWalletDB walletdb;
+ CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin();
CAccount account;
@@ -352,8 +353,8 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
{
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey);
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin();
- it != mapWallet.end() && !account.vchPubKey.empty();
+ for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
+ it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it)
{
const CWalletTx& wtx = (*it).second;
@@ -366,9 +367,9 @@ string GetAccountAddress(string strAccount, bool bForceNew=false)
// Generate a new key
if (account.vchPubKey.empty() || bForceNew)
{
- account.vchPubKey = GetKeyFromKeyPool();
+ account.vchPubKey = pwalletMain->GetKeyFromKeyPool();
string strAddress = PubKeyToAddress(account.vchPubKey);
- SetAddressBookName(strAddress, strAccount);
+ pwalletMain->SetAddressBookName(strAddress, strAccount);
walletdb.WriteAccount(strAccount, account);
}
@@ -391,7 +392,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
Value ret;
CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
ret = GetAccountAddress(strAccount);
}
@@ -421,18 +422,18 @@ Value setaccount(const Array& params, bool fHelp)
// Detect when changing the account of an address that is the 'unused current key' of another account:
CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapWallet)
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
- if (mapAddressBook.count(strAddress))
+ if (pwalletMain->mapAddressBook.count(strAddress))
{
- string strOldAccount = mapAddressBook[strAddress];
+ string strOldAccount = pwalletMain->mapAddressBook[strAddress];
if (strAddress == GetAccountAddress(strOldAccount))
GetAccountAddress(strOldAccount, true);
}
}
- SetAddressBookName(strAddress, strAccount);
+ pwalletMain->SetAddressBookName(strAddress, strAccount);
return Value::null;
}
@@ -447,10 +448,10 @@ Value getaccount(const Array& params, bool fHelp)
string strAddress = params[0].get_str();
string strAccount;
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
- map<string, string>::iterator mi = mapAddressBook.find(strAddress);
- if (mi != mapAddressBook.end() && !(*mi).second.empty())
+ map<string, string>::iterator mi = pwalletMain->mapAddressBook.find(strAddress);
+ if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
strAccount = (*mi).second;
}
return strAccount;
@@ -468,9 +469,9 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
// Find all addresses that have the given account
Array ret;
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
- BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(string, string)& item, pwalletMain->mapAddressBook)
{
const string& strAddress = item.first;
const string& strName = item.second;
@@ -523,7 +524,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
CRITICAL_BLOCK(cs_main)
{
- string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
+ string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
}
@@ -544,7 +545,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
CScript scriptPubKey;
if (!scriptPubKey.SetBitcoinAddress(strAddress))
throw JSONRPCError(-5, "Invalid bitcoin address");
- if (!IsMine(scriptPubKey))
+ if (!IsMine(*pwalletMain,scriptPubKey))
return (double)0.0;
// Minimum confirmations
@@ -554,9 +555,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
// Tally
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;
if (wtx.IsCoinBase() || !wtx.IsFinal())
@@ -575,9 +576,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
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& strName = item.second;
@@ -586,7 +587,7 @@ void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey)
// We're only counting our own valid bitcoin addresses and not ip addresses
CScript scriptPubKey;
if (scriptPubKey.SetBitcoinAddress(strAddress))
- if (IsMine(scriptPubKey))
+ if (IsMine(*pwalletMain,scriptPubKey))
setPubKey.insert(scriptPubKey);
}
}
@@ -613,9 +614,9 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
// Tally
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;
if (wtx.IsCoinBase() || !wtx.IsFinal())
@@ -635,10 +636,10 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
{
int64 nBalance = 0;
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
// Tally wallet transactions
- for (map<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;
if (!wtx.IsFinal())
@@ -661,7 +662,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
int64 GetAccountBalance(const string& strAccount, int nMinDepth)
{
- CWalletDB walletdb;
+ CWalletDB walletdb(pwalletMain->strWalletFile);
return GetAccountBalance(walletdb, strAccount, nMinDepth);
}
@@ -675,7 +676,7 @@ Value getbalance(const Array& params, bool fHelp)
"If [account] is specified, returns the balance in the account.");
if (params.size() == 0)
- return ValueFromAmount(GetBalance());
+ return ValueFromAmount(pwalletMain->GetBalance());
int nMinDepth = 1;
if (params.size() > 1)
@@ -686,7 +687,7 @@ Value getbalance(const Array& params, bool fHelp)
// (GetBalance() sums up all unspent TxOuts)
// getbalance and getbalance '*' should always return the same number.
int64 nBalance = 0;
- for (map<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;
if (!wtx.IsFinal())
@@ -734,9 +735,9 @@ Value movecmd(const Array& params, bool fHelp)
if (params.size() > 4)
strComment = params[4].get_str();
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
- CWalletDB walletdb;
+ CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin();
int64 nNow = GetAdjustedTime();
@@ -787,7 +788,7 @@ Value sendfrom(const Array& params, bool fHelp)
wtx.mapValue["to"] = params[5].get_str();
CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
@@ -795,7 +796,7 @@ Value sendfrom(const Array& params, bool fHelp)
throw JSONRPCError(-6, "Account has insufficient funds");
// Send
- string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
+ string strError = pwalletMain->SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
}
@@ -844,7 +845,7 @@ Value sendmany(const Array& params, bool fHelp)
}
CRITICAL_BLOCK(cs_main)
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
@@ -852,16 +853,16 @@ Value sendmany(const Array& params, bool fHelp)
throw JSONRPCError(-6, "Account has insufficient funds");
// Send
- CReserveKey keyChange;
+ CReserveKey keyChange(pwalletMain);
int64 nFeeRequired = 0;
- bool fCreated = CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
+ bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
if (!fCreated)
{
- if (totalAmount + nFeeRequired > GetBalance())
+ if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
throw JSONRPCError(-6, "Insufficient funds");
throw JSONRPCError(-4, "Transaction creation failed");
}
- if (!CommitTransaction(wtx, keyChange))
+ if (!pwalletMain->CommitTransaction(wtx, keyChange))
throw JSONRPCError(-4, "Transaction commit failed");
}
@@ -894,9 +895,9 @@ Value ListReceived(const Array& params, bool fByAccounts)
// Tally
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;
if (wtx.IsCoinBase() || !wtx.IsFinal())
@@ -923,9 +924,9 @@ Value ListReceived(const Array& params, bool fByAccounts)
// Reply
Array ret;
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& strAccount = item.second;
@@ -1061,13 +1062,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
{
string account;
- if (mapAddressBook.count(r.first))
- account = mapAddressBook[r.first];
+ if (pwalletMain->mapAddressBook.count(r.first))
+ account = pwalletMain->mapAddressBook[r.first];
if (fAllAccounts || (account == strAccount))
{
Object entry;
@@ -1119,16 +1120,16 @@ Value listtransactions(const Array& params, bool fHelp)
nFrom = params[2].get_int();
Array ret;
- CWalletDB walletdb;
+ CWalletDB walletdb(pwalletMain->strWalletFile);
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
// Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef multimap<int64, TxPair > TxItems;
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);
txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
@@ -1180,16 +1181,16 @@ Value listaccounts(const Array& params, bool fHelp)
nMinDepth = params[0].get_int();
map<string, int64> mapAccountBalances;
- CRITICAL_BLOCK(cs_mapWallet)
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
- BOOST_FOREACH(const PAIRTYPE(string, string)& entry, mapAddressBook) {
+ BOOST_FOREACH(const PAIRTYPE(string, string)& entry, pwalletMain->mapAddressBook) {
uint160 hash160;
if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me
mapAccountBalances[entry.second] = 0;
}
- for (map<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;
int64 nGeneratedImmature, nGeneratedMature, nFee;
@@ -1204,8 +1205,8 @@ Value listaccounts(const Array& params, bool fHelp)
{
mapAccountBalances[""] += nGeneratedMature;
BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
- if (mapAddressBook.count(r.first))
- mapAccountBalances[mapAddressBook[r.first]] += r.second;
+ if (pwalletMain->mapAddressBook.count(r.first))
+ mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
else
mapAccountBalances[""] += r.second;
}
@@ -1213,7 +1214,7 @@ Value listaccounts(const Array& params, bool fHelp)
}
list<CAccountingEntry> acentries;
- CWalletDB().ListAccountCreditDebit("*", acentries);
+ CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
@@ -1235,11 +1236,11 @@ Value gettransaction(const Array& params, bool fHelp)
hash.SetHex(params[0].get_str());
Object entry;
- CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
- if (!mapWallet.count(hash))
+ if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
- const CWalletTx& wtx = mapWallet[hash];
+ const CWalletTx& wtx = pwalletMain->mapWallet[hash];
int64 nCredit = wtx.GetCredit();
int64 nDebit = wtx.GetDebit();
@@ -1250,10 +1251,10 @@ Value gettransaction(const Array& params, bool fHelp)
if (wtx.IsFromMe())
entry.push_back(Pair("fee", ValueFromAmount(nFee)));
- WalletTxToJSON(mapWallet[hash], entry);
+ WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
Array details;
- ListTransactions(mapWallet[hash], "*", 0, false, details);
+ ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
entry.push_back(Pair("details", details));
}
@@ -1269,7 +1270,7 @@ Value backupwallet(const Array& params, bool fHelp)
"Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
string strDest = params[0].get_str();
- BackupWallet(strDest);
+ BackupWallet(*pwalletMain, strDest);
return Value::null;
}
@@ -1295,10 +1296,10 @@ Value validateaddress(const Array& params, bool fHelp)
string currentAddress = Hash160ToAddress(hash160);
ret.push_back(Pair("address", currentAddress));
ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0)));
- CRITICAL_BLOCK(cs_mapAddressBook)
+ CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
- if (mapAddressBook.count(currentAddress))
- ret.push_back(Pair("account", mapAddressBook[currentAddress]));
+ if (pwalletMain->mapAddressBook.count(currentAddress))
+ ret.push_back(Pair("account", pwalletMain->mapAddressBook[currentAddress]));
}
}
return ret;
@@ -1325,7 +1326,7 @@ Value getwork(const Array& params, bool fHelp)
static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
static vector<CBlock*> vNewBlock;
- static CReserveKey reservekey;
+ static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
{
@@ -1406,7 +1407,7 @@ Value getwork(const Array& params, bool fHelp)
pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
- return CheckWork(pblock, reservekey);
+ return CheckWork(pblock, *pwalletMain, reservekey);
}
}
diff --git a/src/script.cpp b/src/script.cpp
index 97334ca0a0..bd1b5b3c5f 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -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();
@@ -1030,7 +1030,7 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s
return false;
// Compile solution
- CRITICAL_BLOCK(cs_mapKeys)
+ CRITICAL_BLOCK(keystore.cs_mapKeys)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
@@ -1038,12 +1038,13 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s
{
// Sign
const valtype& vchPubKey = item.second;
- if (!mapKeys.count(vchPubKey))
+ CPrivKey privkey;
+ if (!keystore.GetPrivKey(vchPubKey, privkey))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
- if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig))
+ if (!CKey::Sign(privkey, hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig;
@@ -1056,12 +1057,13 @@ bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& s
if (mi == mapPubKeys.end())
return false;
const vector<unsigned char>& vchPubKey = (*mi).second;
- if (!mapKeys.count(vchPubKey))
+ CPrivKey privkey;
+ if (!keystore.GetPrivKey(vchPubKey, privkey))
return false;
if (hash != 0)
{
vector<unsigned char> vchSig;
- if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig))
+ if (!CKey::Sign(privkey, hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << vchPubKey;
@@ -1085,14 +1087,14 @@ bool IsStandard(const CScript& scriptPubKey)
}
-bool IsMine(const CScript& scriptPubKey)
+bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
{
CScript scriptSig;
- return Solver(scriptPubKey, 0, 0, scriptSig);
+ return Solver(keystore, scriptPubKey, 0, 0, scriptSig);
}
-bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned char>& vchPubKeyRet)
+bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* keystore, vector<unsigned char>& vchPubKeyRet)
{
vchPubKeyRet.clear();
@@ -1100,7 +1102,7 @@ bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned
if (!Solver(scriptPubKey, vSolution))
return false;
- CRITICAL_BLOCK(cs_mapKeys)
+ CRITICAL_BLOCK(cs_mapPubKeys)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
@@ -1116,7 +1118,7 @@ bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned
continue;
vchPubKey = (*mi).second;
}
- if (!fMineOnly || mapKeys.count(vchPubKey))
+ if (keystore == NULL || keystore->HaveKey(vchPubKey))
{
vchPubKeyRet = vchPubKey;
return true;
@@ -1160,7 +1162,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
}
-bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq)
+bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq)
{
assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn];
@@ -1171,7 +1173,7 @@ bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int
// The checksig op will also drop the signatures from its hash.
uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType);
- if (!Solver(txout.scriptPubKey, hash, nHashType, txin.scriptSig))
+ if (!Solver(keystore, txout.scriptPubKey, hash, nHashType, txin.scriptSig))
return false;
txin.scriptSig = scriptPrereq + txin.scriptSig;
@@ -1199,10 +1201,5 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType))
return false;
- // Anytime a signature is successfully verified, it's proof the outpoint is spent,
- // so lets update the wallet spent flag if it doesn't know due to wallet.dat being
- // restored from backup or the user making copies of wallet.dat.
- WalletUpdateSpent(txin.prevout);
-
return true;
}
diff --git a/src/script.h b/src/script.h
index 22a6020dce..ae9fdfffa2 100644
--- a/src/script.h
+++ b/src/script.h
@@ -5,6 +5,7 @@
#define H_BITCOIN_SCRIPT
#include "base58.h"
+#include "keystore.h"
#include <string>
#include <vector>
@@ -707,12 +708,11 @@ public:
-uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
bool IsStandard(const CScript& scriptPubKey);
-bool IsMine(const CScript& scriptPubKey);
-bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, std::vector<unsigned char>& vchPubKeyRet);
+bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
+bool ExtractPubKey(const CScript& scriptPubKey, const CKeyStore* pkeystore, std::vector<unsigned char>& vchPubKeyRet);
bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret);
-bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
+bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0);
#endif
diff --git a/src/util.cpp b/src/util.cpp
index 688605ef5c..2bc2cdd599 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -5,7 +5,7 @@
#include "strlcpy.h"
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
-#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
diff --git a/src/util.h b/src/util.h
index a1f1694929..4c1e74b7da 100644
--- a/src/util.h
+++ b/src/util.h
@@ -139,14 +139,12 @@ inline int myclosesocket(SOCKET& hSocket)
return ret;
}
#define closesocket(s) myclosesocket(s)
-#if 0
-#ifndef GUI
+#if !defined(QT_GUI) && !defined(GUI)
inline const char* _(const char* psz)
{
return psz;
}
#endif
-#endif
diff --git a/src/wallet.cpp b/src/wallet.cpp
new file mode 100644
index 0000000000..eab58aaafb
--- /dev/null
+++ b/src/wallet.cpp
@@ -0,0 +1,1176 @@
+// Copyright (c) 2009-2011 Satoshi Nakamoto & Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+
+#include "headers.h"
+#include "db.h"
+#include "cryptopp/sha.h"
+
+using namespace std;
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// mapWallet
+//
+
+bool CWallet::AddKey(const CKey& key)
+{
+ this->CKeyStore::AddKey(key);
+ if (!fFileBacked)
+ return true;
+ return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
+}
+
+void CWallet::WalletUpdateSpent(const CTransaction &tx)
+{
+ // Anytime a signature is successfully verified, it's proof the outpoint is spent.
+ // Update the wallet spent flag if it doesn't know due to wallet.dat being
+ // restored from backup or the user making copies of wallet.dat.
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
+ if (mi != mapWallet.end())
+ {
+ CWalletTx& wtx = (*mi).second;
+ if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
+ {
+ printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
+ wtx.MarkSpent(txin.prevout.n);
+ wtx.WriteToDisk();
+ vWalletUpdated.push_back(txin.prevout.hash);
+ }
+ }
+ }
+ }
+}
+
+bool CWallet::AddToWallet(const CWalletTx& wtxIn)
+{
+ uint256 hash = wtxIn.GetHash();
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // 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));
+ CWalletTx& wtx = (*ret.first).second;
+ wtx.pwallet = this;
+ bool fInsertedNew = ret.second;
+ if (fInsertedNew)
+ wtx.nTimeReceived = GetAdjustedTime();
+
+ bool fUpdated = false;
+ if (!fInsertedNew)
+ {
+ // Merge
+ if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
+ {
+ wtx.hashBlock = wtxIn.hashBlock;
+ fUpdated = true;
+ }
+ if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
+ {
+ wtx.vMerkleBranch = wtxIn.vMerkleBranch;
+ wtx.nIndex = wtxIn.nIndex;
+ fUpdated = true;
+ }
+ if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
+ {
+ wtx.fFromMe = wtxIn.fFromMe;
+ fUpdated = true;
+ }
+ fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
+ }
+
+ //// debug print
+ printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+
+ // Write to disk
+ if (fInsertedNew || fUpdated)
+ if (!wtx.WriteToDisk())
+ return false;
+
+ // If default receiving address gets used, replace it with a new one
+ CScript scriptDefaultKey;
+ scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ {
+ if (txout.scriptPubKey == scriptDefaultKey)
+ {
+ if (!fFileBacked)
+ continue;
+ CWalletDB walletdb(strWalletFile);
+ vchDefaultKey = GetKeyFromKeyPool();
+ walletdb.WriteDefaultKey(vchDefaultKey);
+ walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
+ }
+ }
+
+ // Notify UI
+ vWalletUpdated.push_back(hash);
+
+ // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
+ WalletUpdateSpent(wtx);
+ }
+
+ // Refresh UI
+ MainFrameRepaint();
+ return true;
+}
+
+bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
+{
+ uint256 hash = tx.GetHash();
+ bool fExisted = mapWallet.count(hash);
+ if (fExisted && !fUpdate) return false;
+ if (fExisted || IsMine(tx) || IsFromMe(tx))
+ {
+ CWalletTx wtx(this,tx);
+ // Get merkle branch if transaction was found in a block
+ if (pblock)
+ wtx.SetMerkleBranch(pblock);
+ return AddToWallet(wtx);
+ }
+ else
+ WalletUpdateSpent(tx);
+ return false;
+}
+
+bool CWallet::EraseFromWallet(uint256 hash)
+{
+ if (!fFileBacked)
+ return false;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ if (mapWallet.erase(hash))
+ CWalletDB(strWalletFile).EraseTx(hash);
+ }
+ return true;
+}
+
+
+bool CWallet::IsMine(const CTxIn &txin) const
+{
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ if (mi != mapWallet.end())
+ {
+ const CWalletTx& prev = (*mi).second;
+ if (txin.prevout.n < prev.vout.size())
+ if (IsMine(prev.vout[txin.prevout.n]))
+ return true;
+ }
+ }
+ return false;
+}
+
+int64 CWallet::GetDebit(const CTxIn &txin) const
+{
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ if (mi != mapWallet.end())
+ {
+ const CWalletTx& prev = (*mi).second;
+ if (txin.prevout.n < prev.vout.size())
+ if (IsMine(prev.vout[txin.prevout.n]))
+ return prev.vout[txin.prevout.n].nValue;
+ }
+ }
+ return 0;
+}
+
+int64 CWalletTx::GetTxTime() const
+{
+ if (!fTimeReceivedIsTxTime && hashBlock != 0)
+ {
+ // If we did not receive the transaction directly, we rely on the block's
+ // time to figure out when it happened. We use the median over a range
+ // of blocks to try to filter out inaccurate block times.
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi != mapBlockIndex.end())
+ {
+ CBlockIndex* pindex = (*mi).second;
+ if (pindex)
+ return pindex->GetMedianTime();
+ }
+ }
+ return nTimeReceived;
+}
+
+int CWalletTx::GetRequestCount() const
+{
+ // Returns -1 if it wasn't being tracked
+ int nRequests = -1;
+ CRITICAL_BLOCK(pwallet->cs_mapRequestCount)
+ {
+ if (IsCoinBase())
+ {
+ // Generated block
+ if (hashBlock != 0)
+ {
+ map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
+ if (mi != pwallet->mapRequestCount.end())
+ nRequests = (*mi).second;
+ }
+ }
+ else
+ {
+ // Did anyone request this transaction?
+ map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
+ if (mi != pwallet->mapRequestCount.end())
+ {
+ nRequests = (*mi).second;
+
+ // How about the block it's in?
+ if (nRequests == 0 && hashBlock != 0)
+ {
+ map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
+ if (mi != pwallet->mapRequestCount.end())
+ nRequests = (*mi).second;
+ else
+ nRequests = 1; // If it's in someone else's block it must have got out
+ }
+ }
+ }
+ }
+ return nRequests;
+}
+
+void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<string, int64> >& listReceived,
+ list<pair<string, int64> >& listSent, int64& nFee, string& strSentAccount) const
+{
+ nGeneratedImmature = nGeneratedMature = nFee = 0;
+ listReceived.clear();
+ listSent.clear();
+ strSentAccount = strFromAccount;
+
+ if (IsCoinBase())
+ {
+ if (GetBlocksToMaturity() > 0)
+ nGeneratedImmature = pwallet->GetCredit(*this);
+ else
+ nGeneratedMature = GetCredit();
+ return;
+ }
+
+ // Compute fee:
+ int64 nDebit = GetDebit();
+ if (nDebit > 0) // debit>0 means we signed/sent this transaction
+ {
+ int64 nValueOut = GetValueOut();
+ nFee = nDebit - nValueOut;
+ }
+
+ // Sent/received. Standard client will never generate a send-to-multiple-recipients,
+ // but non-standard clients might (so return a list of address/amount pairs)
+ BOOST_FOREACH(const CTxOut& txout, vout)
+ {
+ string address;
+ uint160 hash160;
+ vector<unsigned char> vchPubKey;
+ if (ExtractHash160(txout.scriptPubKey, hash160))
+ address = Hash160ToAddress(hash160);
+ else if (ExtractPubKey(txout.scriptPubKey, NULL, vchPubKey))
+ address = PubKeyToAddress(vchPubKey);
+ else
+ {
+ printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
+ this->GetHash().ToString().c_str());
+ address = " unknown ";
+ }
+
+ // Don't report 'change' txouts
+ if (nDebit > 0 && pwallet->IsChange(txout))
+ continue;
+
+ if (nDebit > 0)
+ listSent.push_back(make_pair(address, txout.nValue));
+
+ if (pwallet->IsMine(txout))
+ listReceived.push_back(make_pair(address, txout.nValue));
+ }
+
+}
+
+void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
+ int64& nSent, int64& nFee) const
+{
+ nGenerated = nReceived = nSent = nFee = 0;
+
+ int64 allGeneratedImmature, allGeneratedMature, allFee;
+ allGeneratedImmature = allGeneratedMature = allFee = 0;
+ string strSentAccount;
+ list<pair<string, int64> > listReceived;
+ list<pair<string, int64> > listSent;
+ GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
+
+ if (strAccount == "")
+ nGenerated = allGeneratedMature;
+ if (strAccount == strSentAccount)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string,int64)& s, listSent)
+ nSent += s.second;
+ nFee = allFee;
+ }
+ CRITICAL_BLOCK(pwallet->cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
+ {
+ if (pwallet->mapAddressBook.count(r.first))
+ {
+ map<string, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
+ if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
+ nReceived += r.second;
+ }
+ else if (strAccount.empty())
+ {
+ nReceived += r.second;
+ }
+ }
+ }
+}
+
+void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
+{
+ vtxPrev.clear();
+
+ const int COPY_DEPTH = 3;
+ if (SetMerkleBranch() < COPY_DEPTH)
+ {
+ vector<uint256> vWorkQueue;
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ vWorkQueue.push_back(txin.prevout.hash);
+
+ // This critsect is OK because txdb is already open
+ CRITICAL_BLOCK(pwallet->cs_mapWallet)
+ {
+ map<uint256, const CMerkleTx*> mapWalletPrev;
+ set<uint256> setAlreadyDone;
+ for (int i = 0; i < vWorkQueue.size(); i++)
+ {
+ uint256 hash = vWorkQueue[i];
+ if (setAlreadyDone.count(hash))
+ continue;
+ setAlreadyDone.insert(hash);
+
+ CMerkleTx tx;
+ map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
+ if (mi != pwallet->mapWallet.end())
+ {
+ tx = (*mi).second;
+ BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
+ mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
+ }
+ else if (mapWalletPrev.count(hash))
+ {
+ tx = *mapWalletPrev[hash];
+ }
+ else if (!fClient && txdb.ReadDiskTx(hash, tx))
+ {
+ ;
+ }
+ else
+ {
+ printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
+ continue;
+ }
+
+ int nDepth = tx.SetMerkleBranch();
+ vtxPrev.push_back(tx);
+
+ if (nDepth < COPY_DEPTH)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ vWorkQueue.push_back(txin.prevout.hash);
+ }
+ }
+ }
+
+ reverse(vtxPrev.begin(), vtxPrev.end());
+}
+
+bool CWalletTx::WriteToDisk()
+{
+ return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
+}
+
+int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
+{
+ int ret = 0;
+
+ CBlockIndex* pindex = pindexStart;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ while (pindex)
+ {
+ CBlock block;
+ block.ReadFromDisk(pindex, true);
+ BOOST_FOREACH(CTransaction& tx, block.vtx)
+ {
+ if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
+ ret++;
+ }
+ pindex = pindex->pnext;
+ }
+ }
+ return ret;
+}
+
+void CWallet::ReacceptWalletTransactions()
+{
+ CTxDB txdb("r");
+ bool fRepeat = true;
+ while (fRepeat) CRITICAL_BLOCK(cs_mapWallet)
+ {
+ fRepeat = false;
+ vector<CDiskTxPos> vMissingTx;
+ BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ {
+ CWalletTx& wtx = item.second;
+ if (wtx.IsCoinBase() && wtx.IsSpent(0))
+ continue;
+
+ CTxIndex txindex;
+ bool fUpdated = false;
+ if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
+ {
+ // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
+ if (txindex.vSpent.size() != wtx.vout.size())
+ {
+ printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
+ continue;
+ }
+ for (int i = 0; i < txindex.vSpent.size(); i++)
+ {
+ if (wtx.IsSpent(i))
+ continue;
+ if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
+ {
+ wtx.MarkSpent(i);
+ fUpdated = true;
+ vMissingTx.push_back(txindex.vSpent[i]);
+ }
+ }
+ if (fUpdated)
+ {
+ printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
+ wtx.MarkDirty();
+ wtx.WriteToDisk();
+ }
+ }
+ else
+ {
+ // Reaccept any txes of ours that aren't already in a block
+ if (!wtx.IsCoinBase())
+ wtx.AcceptWalletTransaction(txdb, false);
+ }
+ }
+ if (!vMissingTx.empty())
+ {
+ // TODO: optimize this to scan just part of the block chain?
+ if (ScanForWalletTransactions(pindexGenesisBlock))
+ fRepeat = true; // Found missing transactions: re-do Reaccept.
+ }
+ }
+}
+
+void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
+{
+ BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
+ {
+ if (!tx.IsCoinBase())
+ {
+ uint256 hash = tx.GetHash();
+ if (!txdb.ContainsTx(hash))
+ RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
+ }
+ }
+ if (!IsCoinBase())
+ {
+ uint256 hash = GetHash();
+ if (!txdb.ContainsTx(hash))
+ {
+ printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
+ RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
+ }
+ }
+}
+
+void CWalletTx::RelayWalletTransaction()
+{
+ CTxDB txdb("r");
+ RelayWalletTransaction(txdb);
+}
+
+void CWallet::ResendWalletTransactions()
+{
+ // Do this infrequently and randomly to avoid giving away
+ // that these are our transactions.
+ static int64 nNextTime;
+ if (GetTime() < nNextTime)
+ return;
+ bool fFirst = (nNextTime == 0);
+ nNextTime = GetTime() + GetRand(30 * 60);
+ if (fFirst)
+ return;
+
+ // Only do it if there's been a new block since last time
+ static int64 nLastTime;
+ if (nTimeBestReceived < nLastTime)
+ return;
+ nLastTime = GetTime();
+
+ // Rebroadcast any of our txes that aren't in a block yet
+ printf("ResendWalletTransactions()\n");
+ CTxDB txdb("r");
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Sort them in chronological order
+ multimap<unsigned int, CWalletTx*> mapSorted;
+ BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ {
+ CWalletTx& wtx = item.second;
+ // Don't rebroadcast until it's had plenty of time that
+ // it should have gotten in already by now.
+ if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
+ mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
+ }
+ BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
+ {
+ CWalletTx& wtx = *item.second;
+ wtx.RelayWalletTransaction(txdb);
+ }
+ }
+}
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Actions
+//
+
+
+int64 CWallet::GetBalance() const
+{
+ int64 nStart = GetTimeMillis();
+
+ int64 nTotal = 0;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ continue;
+ nTotal += pcoin->GetAvailableCredit();
+ }
+ }
+
+ //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
+ return nTotal;
+}
+
+
+bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
+{
+ setCoinsRet.clear();
+ nValueRet = 0;
+
+ // List of values less than target
+ pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
+ coinLowestLarger.first = INT64_MAX;
+ coinLowestLarger.second.first = NULL;
+ vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
+ int64 nTotalLower = 0;
+
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ vector<const CWalletTx*> vCoins;
+ vCoins.reserve(mapWallet.size());
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ vCoins.push_back(&(*it).second);
+ random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
+
+ BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
+ {
+ if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ continue;
+
+ if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ continue;
+
+ int nDepth = pcoin->GetDepthInMainChain();
+ if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+ continue;
+
+ for (int i = 0; i < pcoin->vout.size(); i++)
+ {
+ if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
+ continue;
+
+ int64 n = pcoin->vout[i].nValue;
+
+ if (n <= 0)
+ continue;
+
+ pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
+
+ if (n == nTargetValue)
+ {
+ setCoinsRet.insert(coin.second);
+ nValueRet += coin.first;
+ return true;
+ }
+ else if (n < nTargetValue + CENT)
+ {
+ vValue.push_back(coin);
+ nTotalLower += n;
+ }
+ else if (n < coinLowestLarger.first)
+ {
+ coinLowestLarger = coin;
+ }
+ }
+ }
+ }
+
+ if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
+ {
+ for (int i = 0; i < vValue.size(); ++i)
+ {
+ setCoinsRet.insert(vValue[i].second);
+ nValueRet += vValue[i].first;
+ }
+ return true;
+ }
+
+ if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
+ {
+ if (coinLowestLarger.second.first == NULL)
+ return false;
+ setCoinsRet.insert(coinLowestLarger.second);
+ nValueRet += coinLowestLarger.first;
+ return true;
+ }
+
+ if (nTotalLower >= nTargetValue + CENT)
+ nTargetValue += CENT;
+
+ // Solve subset sum by stochastic approximation
+ sort(vValue.rbegin(), vValue.rend());
+ vector<char> vfIncluded;
+ vector<char> vfBest(vValue.size(), true);
+ int64 nBest = nTotalLower;
+
+ for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
+ {
+ vfIncluded.assign(vValue.size(), false);
+ int64 nTotal = 0;
+ bool fReachedTarget = false;
+ for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
+ {
+ for (int i = 0; i < vValue.size(); i++)
+ {
+ if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
+ {
+ nTotal += vValue[i].first;
+ vfIncluded[i] = true;
+ if (nTotal >= nTargetValue)
+ {
+ fReachedTarget = true;
+ if (nTotal < nBest)
+ {
+ nBest = nTotal;
+ vfBest = vfIncluded;
+ }
+ nTotal -= vValue[i].first;
+ vfIncluded[i] = false;
+ }
+ }
+ }
+ }
+ }
+
+ // If the next larger is still closer, return it
+ if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
+ {
+ setCoinsRet.insert(coinLowestLarger.second);
+ nValueRet += coinLowestLarger.first;
+ }
+ else {
+ for (int i = 0; i < vValue.size(); i++)
+ if (vfBest[i])
+ {
+ setCoinsRet.insert(vValue[i].second);
+ nValueRet += vValue[i].first;
+ }
+
+ //// debug print
+ printf("SelectCoins() best subset: ");
+ for (int i = 0; i < vValue.size(); i++)
+ if (vfBest[i])
+ printf("%s ", FormatMoney(vValue[i].first).c_str());
+ printf("total %s\n", FormatMoney(nBest).c_str());
+ }
+
+ return true;
+}
+
+bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
+{
+ return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
+}
+
+
+
+
+bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+{
+ int64 nValue = 0;
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
+ {
+ if (nValue < 0)
+ return false;
+ nValue += s.second;
+ }
+ if (vecSend.empty() || nValue < 0)
+ return false;
+
+ wtxNew.pwallet = this;
+
+ CRITICAL_BLOCK(cs_main)
+ {
+ // txdb must be opened before the mapWallet lock
+ CTxDB txdb("r");
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ nFeeRet = nTransactionFee;
+ loop
+ {
+ wtxNew.vin.clear();
+ wtxNew.vout.clear();
+ wtxNew.fFromMe = true;
+
+ int64 nTotalValue = nValue + nFeeRet;
+ double dPriority = 0;
+ // vouts to the payees
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
+ wtxNew.vout.push_back(CTxOut(s.second, s.first));
+
+ // Choose coins to use
+ set<pair<const CWalletTx*,unsigned int> > setCoins;
+ int64 nValueIn = 0;
+ if (!SelectCoins(nTotalValue, setCoins, nValueIn))
+ return false;
+ BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
+ {
+ int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
+ dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
+ }
+
+ // Fill a vout back to self with any change
+ int64 nChange = nValueIn - nTotalValue;
+ if (nChange >= CENT)
+ {
+ // Note: We use a new key here to keep it from being obvious which side is the change.
+ // The drawback is that by not reusing a previous key, the change may be lost if a
+ // backup is restored, if the backup doesn't have the new private key for the change.
+ // If we reused the old key, it would be possible to add code to look for and
+ // rediscover unknown transactions that were written with keys of ours to recover
+ // post-backup change.
+
+ // Reserve a new key pair from key pool
+ vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
+ assert(mapKeys.count(vchPubKey));
+
+ // Fill a vout to ourself, using same address type as the payment
+ CScript scriptChange;
+ if (vecSend[0].first.GetBitcoinAddressHash160() != 0)
+ scriptChange.SetBitcoinAddress(vchPubKey);
+ else
+ scriptChange << vchPubKey << OP_CHECKSIG;
+
+ // Insert change txn at random position:
+ vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
+ wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
+ }
+ else
+ reservekey.ReturnKey();
+
+ // Fill vin
+ BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+ wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
+
+ // Sign
+ int nIn = 0;
+ BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+ if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
+ return false;
+
+ // Limit size
+ unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
+ if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
+ return false;
+ dPriority /= nBytes;
+
+ // Check that enough fee is included
+ int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
+ bool fAllowFree = CTransaction::AllowFree(dPriority);
+ int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
+ if (nFeeRet < max(nPayFee, nMinFee))
+ {
+ nFeeRet = max(nPayFee, nMinFee);
+ continue;
+ }
+
+ // Fill vtxPrev by copying from previous transactions vtxPrev
+ wtxNew.AddSupportingTransactions(txdb);
+ wtxNew.fTimeReceivedIsTxTime = true;
+
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+{
+ vector< pair<CScript, int64> > vecSend;
+ vecSend.push_back(make_pair(scriptPubKey, nValue));
+ return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
+}
+
+// Call after CreateTransaction unless you want to abort
+bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
+{
+ CRITICAL_BLOCK(cs_main)
+ {
+ printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // This is only to keep the database open to defeat the auto-flush for the
+ // duration of this scope. This is the only place where this optimization
+ // maybe makes sense; please don't do it anywhere else.
+ CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
+
+ // Take key pair from key pool so it won't be used again
+ reservekey.KeepKey();
+
+ // Add tx to wallet, because if it has change it's also ours,
+ // otherwise just for transaction history.
+ AddToWallet(wtxNew);
+
+ // Mark old coins as spent
+ set<CWalletTx*> setCoins;
+ BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
+ {
+ CWalletTx &coin = mapWallet[txin.prevout.hash];
+ coin.pwallet = this;
+ coin.MarkSpent(txin.prevout.n);
+ coin.WriteToDisk();
+ vWalletUpdated.push_back(coin.GetHash());
+ }
+
+ if (fFileBacked)
+ delete pwalletdb;
+ }
+
+ // Track how many getdata requests our transaction gets
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ mapRequestCount[wtxNew.GetHash()] = 0;
+
+ // Broadcast
+ if (!wtxNew.AcceptToMemoryPool())
+ {
+ // This must not fail. The transaction has already been signed and recorded.
+ printf("CommitTransaction() : Error: Transaction not valid");
+ return false;
+ }
+ wtxNew.RelayWalletTransaction();
+ }
+ MainFrameRepaint();
+ return true;
+}
+
+
+
+
+// requires cs_main lock
+string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+{
+ CReserveKey reservekey(this);
+ int64 nFeeRequired;
+ if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
+ {
+ string strError;
+ if (nValue + nFeeRequired > GetBalance())
+ strError = strprintf(_("Error: 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
+ strError = _("Error: Transaction creation failed ");
+ printf("SendMoney() : %s", strError.c_str());
+ return strError;
+ }
+
+ if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
+ return "ABORTED";
+
+ if (!CommitTransaction(wtxNew, reservekey))
+ return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+
+ MainFrameRepaint();
+ return "";
+}
+
+
+
+// requires cs_main lock
+string CWallet::SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+{
+ // Check amount
+ if (nValue <= 0)
+ return _("Invalid amount");
+ if (nValue + nTransactionFee > GetBalance())
+ return _("Insufficient funds");
+
+ // Parse bitcoin address
+ CScript scriptPubKey;
+ if (!scriptPubKey.SetBitcoinAddress(strAddress))
+ return _("Invalid bitcoin address");
+
+ return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
+}
+
+
+
+
+bool CWallet::LoadWallet(bool& fFirstRunRet)
+{
+ if (!fFileBacked)
+ return false;
+ fFirstRunRet = false;
+ if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this))
+ return false;
+ fFirstRunRet = vchDefaultKey.empty();
+
+ if (!mapKeys.count(vchDefaultKey))
+ {
+ // Create new default key
+ RandAddSeedPerfmon();
+
+ vchDefaultKey = GetKeyFromKeyPool();
+ if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
+ return false;
+ CWalletDB(strWalletFile).WriteDefaultKey(vchDefaultKey);
+ }
+
+ CreateThread(ThreadFlushWalletDB, &strWalletFile);
+ return true;
+}
+
+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;
+ keypool.vchPubKey.clear();
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(cs_setKeyPool)
+ {
+ CWalletDB walletdb(strWalletFile);
+
+ // Top up key pool
+ int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
+ while (setKeyPool.size() < nTargetSize+1)
+ {
+ int64 nEnd = 1;
+ if (!setKeyPool.empty())
+ nEnd = *(--setKeyPool.end()) + 1;
+ if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
+ throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
+ setKeyPool.insert(nEnd);
+ printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
+ }
+
+ // Get the oldest key
+ assert(!setKeyPool.empty());
+ nIndex = *(setKeyPool.begin());
+ setKeyPool.erase(setKeyPool.begin());
+ if (!walletdb.ReadPool(nIndex, keypool))
+ throw runtime_error("ReserveKeyFromKeyPool() : read failed");
+ if (!mapKeys.count(keypool.vchPubKey))
+ throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
+ assert(!keypool.vchPubKey.empty());
+ printf("keypool reserve %"PRI64d"\n", nIndex);
+ }
+}
+
+void CWallet::KeepKey(int64 nIndex)
+{
+ // Remove from key pool
+ if (fFileBacked)
+ {
+ CWalletDB walletdb(strWalletFile);
+ CRITICAL_BLOCK(cs_main)
+ {
+ walletdb.ErasePool(nIndex);
+ }
+ }
+ printf("keypool keep %"PRI64d"\n", nIndex);
+}
+
+void CWallet::ReturnKey(int64 nIndex)
+{
+ // Return to key pool
+ CRITICAL_BLOCK(cs_setKeyPool)
+ setKeyPool.insert(nIndex);
+ printf("keypool return %"PRI64d"\n", nIndex);
+}
+
+bool CWallet::SetAddressBookName(const std::string& strAddress, const std::string& strName)
+{
+ if (!fFileBacked)
+ return false;
+ if(CWalletDB(strWalletFile).WriteName(strAddress, strName))
+ {
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ mapAddressBook[strAddress] = strName;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool CWallet::EraseAddressBookName(const std::string& strAddress)
+{
+ if (!fFileBacked)
+ return false;
+ if(CWalletDB(strWalletFile).EraseName(strAddress))
+ {
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ mapAddressBook.erase(strAddress);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+std::string CWallet::GetDefaultAddress()
+{
+ if (!fFileBacked)
+ return false;
+ std::vector<unsigned char> vchPubKey;
+ if (CWalletDB(strWalletFile, "r").ReadDefaultKey(vchPubKey))
+ {
+ return PubKeyToAddress(vchPubKey);
+ }
+ else
+ {
+ return "";
+ }
+}
+
+bool CWallet::SetDefaultAddress(const std::string& strAddress)
+{
+ uint160 hash160;
+ if (!AddressToHash160(strAddress, hash160))
+ return false;
+ if (!mapPubKeys.count(hash160))
+ return false;
+ return CWalletDB(strWalletFile).WriteDefaultKey(mapPubKeys[hash160]);
+}
+
+
+vector<unsigned char> CWallet::GetKeyFromKeyPool()
+{
+ int64 nIndex = 0;
+ CKeyPool keypool;
+ ReserveKeyFromKeyPool(nIndex, keypool);
+ KeepKey(nIndex);
+ return keypool.vchPubKey;
+}
+
+int64 CWallet::GetOldestKeyPoolTime()
+{
+ int64 nIndex = 0;
+ CKeyPool keypool;
+ ReserveKeyFromKeyPool(nIndex, keypool);
+ ReturnKey(nIndex);
+ return keypool.nTime;
+}
+
+vector<unsigned char> CReserveKey::GetReservedKey()
+{
+ if (nIndex == -1)
+ {
+ CKeyPool keypool;
+ pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
+ vchPubKey = keypool.vchPubKey;
+ }
+ assert(!vchPubKey.empty());
+ return vchPubKey;
+}
+
+void CReserveKey::KeepKey()
+{
+ if (nIndex != -1)
+ pwallet->KeepKey(nIndex);
+ nIndex = -1;
+ vchPubKey.clear();
+}
+
+void CReserveKey::ReturnKey()
+{
+ if (nIndex != -1)
+ pwallet->ReturnKey(nIndex);
+ nIndex = -1;
+ vchPubKey.clear();
+}
diff --git a/src/wallet.h b/src/wallet.h
new file mode 100644
index 0000000000..69110a4afa
--- /dev/null
+++ b/src/wallet.h
@@ -0,0 +1,611 @@
+// Copyright (c) 2009-2011 Satoshi Nakamoto & Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_WALLET_H
+#define BITCOIN_WALLET_H
+
+#include "bignum.h"
+#include "key.h"
+#include "script.h"
+
+class CWalletTx;
+class CReserveKey;
+class CWalletDB;
+
+class CWallet : public CKeyStore
+{
+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;
+
+
+public:
+ bool fFileBacked;
+ std::string strWalletFile;
+
+ std::set<int64> setKeyPool;
+ CCriticalSection cs_setKeyPool;
+
+ CWallet()
+ {
+ fFileBacked = false;
+ }
+ CWallet(std::string strWalletFileIn)
+ {
+ strWalletFile = strWalletFileIn;
+ fFileBacked = true;
+ }
+
+ 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;
+
+ 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");
+ return (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);
+ bool EraseAddressBookName(const std::string& strAddress);
+ std::string GetDefaultAddress();
+ bool SetDefaultAddress(const std::string& strAddress);
+
+ 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();
+};
+
+
+//
+// A transaction with a bunch of additional info that only the owner cares
+// about. It includes any unrecorded transactions needed to link it back
+// to the block chain.
+//
+class CWalletTx : public CMerkleTx
+{
+public:
+ const CWallet* pwallet;
+
+ std::vector<CMerkleTx> vtxPrev;
+ std::map<std::string, std::string> mapValue;
+ std::vector<std::pair<std::string, std::string> > vOrderForm;
+ unsigned int fTimeReceivedIsTxTime;
+ unsigned int nTimeReceived; // time received by this node
+ char fFromMe;
+ std::string strFromAccount;
+ std::vector<char> vfSpent;
+
+ // memory only
+ mutable char fDebitCached;
+ mutable char fCreditCached;
+ mutable char fAvailableCreditCached;
+ mutable char fChangeCached;
+ mutable int64 nDebitCached;
+ mutable int64 nCreditCached;
+ mutable int64 nAvailableCreditCached;
+ mutable int64 nChangeCached;
+
+ // memory only UI hints
+ mutable unsigned int nTimeDisplayed;
+ mutable int nLinesDisplayed;
+ mutable char fConfirmedDisplayed;
+
+ CWalletTx()
+ {
+ Init(NULL);
+ }
+
+ CWalletTx(const CWallet* pwalletIn)
+ {
+ Init(pwalletIn);
+ }
+
+ CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
+ {
+ Init(pwalletIn);
+ }
+
+ CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
+ {
+ Init(pwalletIn);
+ }
+
+ void Init(const CWallet* pwalletIn)
+ {
+ pwallet = pwalletIn;
+ vtxPrev.clear();
+ mapValue.clear();
+ vOrderForm.clear();
+ fTimeReceivedIsTxTime = false;
+ nTimeReceived = 0;
+ fFromMe = false;
+ strFromAccount.clear();
+ vfSpent.clear();
+ fDebitCached = false;
+ fCreditCached = false;
+ fAvailableCreditCached = false;
+ fChangeCached = false;
+ nDebitCached = 0;
+ nCreditCached = 0;
+ nAvailableCreditCached = 0;
+ nChangeCached = 0;
+ nTimeDisplayed = 0;
+ nLinesDisplayed = 0;
+ fConfirmedDisplayed = false;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ CWalletTx* pthis = const_cast<CWalletTx*>(this);
+ if (fRead)
+ pthis->Init(NULL);
+ char fSpent = false;
+
+ if (!fRead)
+ {
+ pthis->mapValue["fromaccount"] = pthis->strFromAccount;
+
+ std::string str;
+ BOOST_FOREACH(char f, vfSpent)
+ {
+ str += (f ? '1' : '0');
+ if (f)
+ fSpent = true;
+ }
+ pthis->mapValue["spent"] = str;
+ }
+
+ nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
+ READWRITE(vtxPrev);
+ READWRITE(mapValue);
+ READWRITE(vOrderForm);
+ READWRITE(fTimeReceivedIsTxTime);
+ READWRITE(nTimeReceived);
+ READWRITE(fFromMe);
+ READWRITE(fSpent);
+
+ if (fRead)
+ {
+ pthis->strFromAccount = pthis->mapValue["fromaccount"];
+
+ if (mapValue.count("spent"))
+ BOOST_FOREACH(char c, pthis->mapValue["spent"])
+ pthis->vfSpent.push_back(c != '0');
+ else
+ pthis->vfSpent.assign(vout.size(), fSpent);
+ }
+
+ pthis->mapValue.erase("fromaccount");
+ pthis->mapValue.erase("version");
+ pthis->mapValue.erase("spent");
+ )
+
+ // marks certain txout's as spent
+ // returns true if any update took place
+ bool UpdateSpent(const std::vector<char>& vfNewSpent)
+ {
+ bool fReturn = false;
+ for (int i=0; i < vfNewSpent.size(); i++)
+ {
+ if (i == vfSpent.size())
+ break;
+
+ if (vfNewSpent[i] && !vfSpent[i])
+ {
+ vfSpent[i] = true;
+ fReturn = true;
+ fAvailableCreditCached = false;
+ }
+ }
+ return fReturn;
+ }
+
+ void MarkDirty()
+ {
+ fCreditCached = false;
+ fAvailableCreditCached = false;
+ fDebitCached = false;
+ fChangeCached = false;
+ }
+
+ void MarkSpent(unsigned int nOut)
+ {
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
+ vfSpent.resize(vout.size());
+ if (!vfSpent[nOut])
+ {
+ vfSpent[nOut] = true;
+ fAvailableCreditCached = false;
+ }
+ }
+
+ bool IsSpent(unsigned int nOut) const
+ {
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
+ if (nOut >= vfSpent.size())
+ return false;
+ return (!!vfSpent[nOut]);
+ }
+
+ int64 GetDebit() const
+ {
+ if (vin.empty())
+ return 0;
+ if (fDebitCached)
+ return nDebitCached;
+ nDebitCached = pwallet->GetDebit(*this);
+ fDebitCached = true;
+ return nDebitCached;
+ }
+
+ int64 GetCredit(bool fUseCache=true) const
+ {
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ return 0;
+
+ // GetBalance can assume transactions in mapWallet won't change
+ if (fUseCache && fCreditCached)
+ return nCreditCached;
+ nCreditCached = pwallet->GetCredit(*this);
+ fCreditCached = true;
+ return nCreditCached;
+ }
+
+ int64 GetAvailableCredit(bool fUseCache=true) const
+ {
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ return 0;
+
+ if (fUseCache && fAvailableCreditCached)
+ return nAvailableCreditCached;
+
+ int64 nCredit = 0;
+ for (int i = 0; i < vout.size(); i++)
+ {
+ if (!IsSpent(i))
+ {
+ const CTxOut &txout = vout[i];
+ nCredit += pwallet->GetCredit(txout);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ }
+ }
+
+ nAvailableCreditCached = nCredit;
+ fAvailableCreditCached = true;
+ return nCredit;
+ }
+
+
+ int64 GetChange() const
+ {
+ if (fChangeCached)
+ return nChangeCached;
+ nChangeCached = pwallet->GetChange(*this);
+ fChangeCached = true;
+ return nChangeCached;
+ }
+
+ 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;
+
+ void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived,
+ int64& nSent, int64& nFee) const;
+
+ bool IsFromMe() const
+ {
+ return (GetDebit() > 0);
+ }
+
+ bool IsConfirmed() const
+ {
+ // Quick answer in most cases
+ if (!IsFinal())
+ return false;
+ if (GetDepthInMainChain() >= 1)
+ return true;
+ if (!IsFromMe()) // using wtx's cached debit
+ return false;
+
+ // If no confirmations but it's from us, we can still
+ // consider it confirmed if all dependencies are confirmed
+ std::map<uint256, const CMerkleTx*> mapPrev;
+ std::vector<const CMerkleTx*> vWorkQueue;
+ vWorkQueue.reserve(vtxPrev.size()+1);
+ vWorkQueue.push_back(this);
+ for (int i = 0; i < vWorkQueue.size(); i++)
+ {
+ const CMerkleTx* ptx = vWorkQueue[i];
+
+ if (!ptx->IsFinal())
+ return false;
+ if (ptx->GetDepthInMainChain() >= 1)
+ continue;
+ if (!pwallet->IsFromMe(*ptx))
+ return false;
+
+ if (mapPrev.empty())
+ BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
+ mapPrev[tx.GetHash()] = &tx;
+
+ BOOST_FOREACH(const CTxIn& txin, ptx->vin)
+ {
+ if (!mapPrev.count(txin.prevout.hash))
+ return false;
+ vWorkQueue.push_back(mapPrev[txin.prevout.hash]);
+ }
+ }
+ return true;
+ }
+
+ bool WriteToDisk();
+
+ int64 GetTxTime() const;
+ int GetRequestCount() const;
+
+ void AddSupportingTransactions(CTxDB& txdb);
+
+ bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
+ bool AcceptWalletTransaction();
+
+ void RelayWalletTransaction(CTxDB& txdb);
+ void RelayWalletTransaction();
+};
+
+
+//
+// Private key that includes an expiration date in case it never gets used.
+//
+class CWalletKey
+{
+public:
+ CPrivKey vchPrivKey;
+ int64 nTimeCreated;
+ int64 nTimeExpires;
+ std::string strComment;
+ //// todo: add something to note what created it (user, getnewaddress, change)
+ //// maybe should have a map<string, string> property map
+
+ CWalletKey(int64 nExpires=0)
+ {
+ nTimeCreated = (nExpires ? GetTime() : 0);
+ nTimeExpires = nExpires;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vchPrivKey);
+ READWRITE(nTimeCreated);
+ READWRITE(nTimeExpires);
+ READWRITE(strComment);
+ )
+};
+
+
+
+
+
+
+//
+// Account information.
+// Stored in wallet with key "acc"+string account name
+//
+class CAccount
+{
+public:
+ std::vector<unsigned char> vchPubKey;
+
+ CAccount()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ vchPubKey.clear();
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vchPubKey);
+ )
+};
+
+
+
+//
+// Internal transfers.
+// Database key is acentry<account><counter>
+//
+class CAccountingEntry
+{
+public:
+ std::string strAccount;
+ int64 nCreditDebit;
+ int64 nTime;
+ std::string strOtherAccount;
+ std::string strComment;
+
+ CAccountingEntry()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ nCreditDebit = 0;
+ nTime = 0;
+ strAccount.clear();
+ strOtherAccount.clear();
+ strComment.clear();
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ // Note: strAccount is serialized as part of the key, not here.
+ READWRITE(nCreditDebit);
+ READWRITE(nTime);
+ READWRITE(strOtherAccount);
+ READWRITE(strComment);
+ )
+};
+
+bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
+
+#endif