aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/allocators.h5
-rw-r--r--src/base58.h16
-rw-r--r--src/bitcoinrpc.cpp80
-rw-r--r--src/crypter.cpp4
-rw-r--r--src/crypter.h4
-rw-r--r--src/db.cpp32
-rw-r--r--src/db.h8
-rw-r--r--src/init.cpp142
-rw-r--r--src/leveldb.cpp14
-rw-r--r--src/leveldb.h2
-rwxr-xr-xsrc/leveldb/Makefile64
-rw-r--r--src/main.cpp315
-rw-r--r--src/main.h40
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/qt/addressbookpage.h2
-rw-r--r--src/qt/bitcoinamountfield.h6
-rw-r--r--src/qt/bitcoingui.cpp30
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/bitcoinstrings.cpp2
-rw-r--r--src/qt/clientmodel.cpp8
-rw-r--r--src/qt/clientmodel.h9
-rw-r--r--src/qt/forms/optionsdialog.ui10
-rw-r--r--src/qt/forms/sendcoinsentry.ui26
-rw-r--r--src/qt/macdockiconhandler.h2
-rw-r--r--src/qt/optionsdialog.cpp1
-rw-r--r--src/qt/optionsmodel.cpp10
-rw-r--r--src/qt/optionsmodel.h1
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/transactiontablemodel.h3
-rw-r--r--src/rpcwallet.cpp2
-rw-r--r--src/serialize.h144
-rw-r--r--src/test/test_bitcoin.cpp6
-rw-r--r--src/txdb.cpp16
-rw-r--r--src/txdb.h6
-rw-r--r--src/util.cpp2
-rw-r--r--src/wallet.cpp13
-rw-r--r--src/wallet.h18
37 files changed, 672 insertions, 377 deletions
diff --git a/src/allocators.h b/src/allocators.h
index 99afa10c25..eb2aed6721 100644
--- a/src/allocators.h
+++ b/src/allocators.h
@@ -9,6 +9,7 @@
#include <string>
#include <boost/thread/mutex.hpp>
#include <map>
+#include <openssl/crypto.h> // for OPENSSL_cleanse()
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -212,7 +213,7 @@ struct secure_allocator : public std::allocator<T>
{
if (p != NULL)
{
- memset(p, 0, sizeof(T) * n);
+ OPENSSL_cleanse(p, sizeof(T) * n);
LockedPageManager::instance.UnlockRange(p, sizeof(T) * n);
}
std::allocator<T>::deallocate(p, n);
@@ -246,7 +247,7 @@ struct zero_after_free_allocator : public std::allocator<T>
void deallocate(T* p, std::size_t n)
{
if (p != NULL)
- memset(p, 0, sizeof(T) * n);
+ OPENSSL_cleanse(p, sizeof(T) * n);
std::allocator<T>::deallocate(p, n);
}
};
diff --git a/src/base58.h b/src/base58.h
index 9dfea86ff5..be8a541f67 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -17,9 +17,11 @@
#include <string>
#include <vector>
+
#include "bignum.h"
#include "key.h"
#include "script.h"
+#include "allocators.h"
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@@ -178,7 +180,8 @@ protected:
unsigned char nVersion;
// the actually encoded data
- std::vector<unsigned char> vchData;
+ typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
+ vector_uchar vchData;
CBase58Data()
{
@@ -186,13 +189,6 @@ protected:
vchData.clear();
}
- ~CBase58Data()
- {
- // zero the memory, as it may contain sensitive data
- if (!vchData.empty())
- memset(&vchData[0], 0, vchData.size());
- }
-
void SetData(int nVersionIn, const void* pdata, size_t nSize)
{
nVersion = nVersionIn;
@@ -221,7 +217,7 @@ public:
vchData.resize(vchTemp.size() - 1);
if (!vchData.empty())
memcpy(&vchData[0], &vchTemp[1], vchData.size());
- memset(&vchTemp[0], 0, vchTemp.size());
+ OPENSSL_cleanse(&vchTemp[0], vchData.size());
return true;
}
@@ -457,4 +453,4 @@ public:
}
};
-#endif
+#endif // BITCOIN_BASE58_H
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 21e37c75e1..8c04f577d1 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -11,7 +11,6 @@
#include "bitcoinrpc.h"
#include "db.h"
-#undef printf
#include <boost/asio.hpp>
#include <boost/asio/ip/v6_only.hpp>
#include <boost/bind.hpp>
@@ -26,8 +25,6 @@
#include <boost/shared_ptr.hpp>
#include <list>
-#define printf OutputDebugStringF
-
using namespace std;
using namespace boost;
using namespace boost::asio;
@@ -179,14 +176,12 @@ Value help(const Array& params, bool fHelp)
Value stop(const Array& params, bool fHelp)
{
+ // Accept the deprecated and ignored 'detach´ boolean argument
if (fHelp || params.size() > 1)
throw runtime_error(
- "stop <detach>\n"
- "<detach> is true or false to detach the database or not for this stop only\n"
- "Stop Bitcoin server (and possibly override the detachdb config value).");
+ "stop\n"
+ "Stop Bitcoin server.");
// Shutdown will take long enough that the response should get back
- if (params.size() > 0)
- bitdb.SetDetach(params[0].get_bool());
StartShutdown();
return "Bitcoin server stopping";
}
@@ -362,6 +357,41 @@ static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
strMsg.c_str());
}
+bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
+ string& http_method, string& http_uri)
+{
+ string str;
+ getline(stream, str);
+
+ // HTTP request line is space-delimited
+ vector<string> vWords;
+ boost::split(vWords, str, boost::is_any_of(" "));
+ if (vWords.size() < 2)
+ return false;
+
+ // HTTP methods permitted: GET, POST
+ http_method = vWords[0];
+ if (http_method != "GET" && http_method != "POST")
+ return false;
+
+ // HTTP URI must be an absolute path, relative to current host
+ http_uri = vWords[1];
+ if (http_uri.size() == 0 || http_uri[0] != '/')
+ return false;
+
+ // parse proto, if present
+ string strProto = "";
+ if (vWords.size() > 2)
+ strProto = vWords[2];
+
+ proto = 0;
+ const char *ver = strstr(strProto.c_str(), "HTTP/1.");
+ if (ver != NULL)
+ proto = atoi(ver+7);
+
+ return true;
+}
+
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
{
string str;
@@ -377,7 +407,7 @@ int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
return atoi(vWords[1].c_str());
}
-int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
+int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
{
int nLen = 0;
loop
@@ -402,17 +432,15 @@ int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHea
return nLen;
}
-int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
+int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
+ string>& mapHeadersRet, string& strMessageRet,
+ int nProto)
{
mapHeadersRet.clear();
strMessageRet = "";
- // Read status
- int nProto = 0;
- int nStatus = ReadHTTPStatus(stream, nProto);
-
// Read header
- int nLen = ReadHTTPHeader(stream, mapHeadersRet);
+ int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
if (nLen < 0 || nLen > (int)MAX_SIZE)
return HTTP_INTERNAL_SERVER_ERROR;
@@ -434,7 +462,7 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe
mapHeadersRet["connection"] = "close";
}
- return nStatus;
+ return HTTP_OK;
}
bool HTTPAuthorized(map<string, string>& mapHeaders)
@@ -941,10 +969,17 @@ void ThreadRPCServer3(void* parg)
}
return;
}
+
+ int nProto = 0;
map<string, string> mapHeaders;
- string strRequest;
+ string strRequest, strMethod, strURI;
+
+ // Read HTTP request line
+ if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI))
+ break;
- ReadHTTP(conn->stream(), mapHeaders, strRequest);
+ // Read HTTP message headers and body
+ ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto);
// Check authorization
if (mapHeaders.count("authorization") == 0)
@@ -1076,10 +1111,15 @@ Object CallRPC(const string& strMethod, const Array& params)
string strPost = HTTPPost(strRequest, mapRequestHeaders);
stream << strPost << std::flush;
- // Receive reply
+ // Receive HTTP reply status
+ int nProto = 0;
+ int nStatus = ReadHTTPStatus(stream, nProto);
+
+ // Receive HTTP reply message headers and body
map<string, string> mapHeaders;
string strReply;
- int nStatus = ReadHTTP(stream, mapHeaders, strReply);
+ ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
+
if (nStatus == HTTP_UNAUTHORIZED)
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 181b8fa00a..a2b62a87c8 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -24,8 +24,8 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v
if (i != (int)WALLET_CRYPTO_KEY_SIZE)
{
- memset(&chKey, 0, sizeof chKey);
- memset(&chIV, 0, sizeof chIV);
+ OPENSSL_cleanse(chKey, sizeof(chKey));
+ OPENSSL_cleanse(chIV, sizeof(chIV));
return false;
}
diff --git a/src/crypter.h b/src/crypter.h
index 04538a3fa5..6f75170bac 100644
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -76,8 +76,8 @@ public:
void CleanKey()
{
- memset(&chKey, 0, sizeof chKey);
- memset(&chIV, 0, sizeof chIV);
+ OPENSSL_cleanse(chKey, sizeof(chKey));
+ OPENSSL_cleanse(chIV, sizeof(chIV));
fKeySet = false;
}
diff --git a/src/db.cpp b/src/db.cpp
index cf96fe6e38..60e1f6f280 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -55,7 +55,7 @@ void CDBEnv::Close()
EnvShutdown();
}
-bool CDBEnv::Open(boost::filesystem::path pathEnv_)
+bool CDBEnv::Open(const boost::filesystem::path& path)
{
if (fDbEnvInit)
return true;
@@ -63,18 +63,16 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
if (fShutdown)
return false;
- pathEnv = pathEnv_;
- filesystem::path pathDataDir = pathEnv;
- filesystem::path pathLogDir = pathDataDir / "database";
+ filesystem::path pathLogDir = path / "database";
filesystem::create_directory(pathLogDir);
- filesystem::path pathErrorFile = pathDataDir / "db.log";
+ filesystem::path pathErrorFile = path / "db.log";
printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
unsigned int nEnvFlags = 0;
if (GetBoolArg("-privdb", true))
nEnvFlags |= DB_PRIVATE;
- int nDbCache = GetArg("-dbcache", 25);
+ unsigned int nDbCache = GetArg("-dbcache", 25);
dbenv.set_lg_dir(pathLogDir.string().c_str());
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
dbenv.set_lg_bsize(1048576);
@@ -85,7 +83,7 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
dbenv.set_flags(DB_AUTO_COMMIT, 1);
dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
- int ret = dbenv.open(pathDataDir.string().c_str(),
+ int ret = dbenv.open(path.string().c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -271,14 +269,6 @@ CDB::CDB(const char *pszFile, const char* pszMode) :
}
}
-static bool IsChainFile(std::string strFile)
-{
- if (strFile == "coins.dat" || strFile == "blktree.dat")
- return true;
-
- return false;
-}
-
void CDB::Flush()
{
if (activeTxn)
@@ -288,10 +278,6 @@ void CDB::Flush()
unsigned int nMinutes = 0;
if (fReadOnly)
nMinutes = 1;
- if (IsChainFile(strFile))
- nMinutes = 2;
- if (IsChainFile(strFile) && IsInitialBlockDownload())
- nMinutes = 5;
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
}
@@ -453,11 +439,9 @@ void CDBEnv::Flush(bool fShutdown)
CloseDb(strFile);
printf("%s checkpoint\n", strFile.c_str());
dbenv.txn_checkpoint(0, 0, 0);
- if (!IsChainFile(strFile) || fDetachDB) {
- printf("%s detach\n", strFile.c_str());
- if (!fMockDb)
- dbenv.lsn_reset(strFile.c_str(), 0);
- }
+ printf("%s detach\n", strFile.c_str());
+ if (!fMockDb)
+ dbenv.lsn_reset(strFile.c_str(), 0);
printf("%s closed\n", strFile.c_str());
mapFileUseCount.erase(mi++);
}
diff --git a/src/db.h b/src/db.h
index 9a5f1ca9e4..0bcece7803 100644
--- a/src/db.h
+++ b/src/db.h
@@ -31,10 +31,8 @@ bool BackupWallet(const CWallet& wallet, const std::string& strDest);
class CDBEnv
{
private:
- bool fDetachDB;
bool fDbEnvInit;
bool fMockDb;
- boost::filesystem::path pathEnv;
void EnvShutdown();
@@ -47,7 +45,7 @@ public:
CDBEnv();
~CDBEnv();
void MakeMock();
- bool IsMock() { return fMockDb; };
+ bool IsMock() { return fMockDb; }
/*
* Verify that database file strFile is OK. If it is not,
@@ -67,12 +65,10 @@ public:
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
- bool Open(boost::filesystem::path pathEnv_);
+ bool Open(const boost::filesystem::path &path);
void Close();
void Flush(bool fShutdown);
void CheckpointLSN(std::string strFile);
- void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; }
- bool GetDetach() { return fDetachDB; }
void CloseDb(const std::string& strFile);
bool RemoveDb(const std::string& strFile);
diff --git a/src/init.cpp b/src/init.cpp
index 1724382bf5..f6df4055fc 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -26,6 +26,13 @@ using namespace boost;
CWallet* pwalletMain;
CClientUIInterface uiInterface;
+// Used to pass flags to the Bind() function
+enum BindFlags {
+ BF_NONE = 0,
+ BF_EXPLICIT = 1,
+ BF_REPORT_ERROR = 2
+};
+
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
@@ -213,12 +220,12 @@ bool static InitWarning(const std::string &str)
}
-bool static Bind(const CService &addr, bool fError = true) {
- if (IsLimited(addr))
+bool static Bind(const CService &addr, int flags) {
+ if (!(flags & BF_EXPLICIT) && IsLimited(addr))
return false;
std::string strError;
if (!BindListenPort(addr, strError)) {
- if (fError)
+ if (flags & BF_REPORT_ERROR)
return InitError(strError);
return false;
}
@@ -236,7 +243,6 @@ std::string HelpMessage()
" -gen=0 " + _("Don't generate coins") + "\n" +
" -datadir=<dir> " + _("Specify data directory") + "\n" +
" -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n" +
- " -dblogsize=<n> " + _("Set database disk log size in megabytes (default: 100)") + "\n" +
" -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
@@ -252,7 +258,7 @@ std::string HelpMessage()
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
- " -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
+ " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
@@ -265,7 +271,6 @@ std::string HelpMessage()
" -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n" +
#endif
#endif
- " -detachdb " + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
" -paytxfee=<amt> " + _("Fee per KB to add to transactions you send") + "\n" +
#ifdef QT_GUI
" -server " + _("Accept command line and JSON-RPC commands") + "\n" +
@@ -295,6 +300,7 @@ std::string HelpMessage()
" -checkblocks=<n> " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
" -checklevel=<n> " + _("How thorough the block verification is (0-6, default: 1)") + "\n" +
" -loadblock=<file> " + _("Imports blocks from external blk000?.dat file") + "\n" +
+ " -reindex " + _("Rebuild blockchain index from current blk000??.dat files") + "\n" +
"\n" + _("Block creation options:") + "\n" +
" -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n" +
@@ -310,6 +316,81 @@ std::string HelpMessage()
return strUsage;
}
+struct CImportingNow
+{
+ CImportingNow() {
+ assert(fImporting == false);
+ fImporting = true;
+ }
+
+ ~CImportingNow() {
+ assert(fImporting == true);
+ fImporting = false;
+ }
+};
+
+struct CImportData {
+ std::vector<boost::filesystem::path> vFiles;
+};
+
+void ThreadImport(void *data) {
+ CImportData *import = reinterpret_cast<CImportData*>(data);
+
+ RenameThread("bitcoin-loadblk");
+
+ vnThreadsRunning[THREAD_IMPORT]++;
+
+ // -reindex
+ if (fReindex) {
+ CImportingNow imp;
+ int nFile = 0;
+ while (!fShutdown) {
+ CDiskBlockPos pos;
+ pos.nFile = nFile;
+ pos.nPos = 0;
+ FILE *file = OpenBlockFile(pos, true);
+ if (!file)
+ break;
+ printf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
+ LoadExternalBlockFile(file, &pos);
+ nFile++;
+ }
+ if (!fShutdown) {
+ pblocktree->WriteReindexing(false);
+ fReindex = false;
+ printf("Reindexing finished\n");
+ }
+ }
+
+ // hardcoded $DATADIR/bootstrap.dat
+ filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
+ if (filesystem::exists(pathBootstrap) && !fShutdown) {
+ FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
+ if (file) {
+ CImportingNow imp;
+ filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
+ printf("Importing bootstrap.dat...\n");
+ LoadExternalBlockFile(file);
+ RenameOver(pathBootstrap, pathBootstrapOld);
+ }
+ }
+
+ // -loadblock=
+ BOOST_FOREACH(boost::filesystem::path &path, import->vFiles) {
+ if (fShutdown)
+ break;
+ FILE *file = fopen(path.string().c_str(), "rb");
+ if (file) {
+ CImportingNow imp;
+ printf("Importing %s...\n", path.string().c_str());
+ LoadExternalBlockFile(file);
+ }
+ }
+
+ delete import;
+
+ vnThreadsRunning[THREAD_IMPORT]--;
+}
/** Initialize bitcoin.
* @pre Parameters should be parsed and config file should be read.
@@ -408,8 +489,6 @@ bool AppInit2()
else
fDebugNet = GetBoolArg("-debugnet");
- bitdb.SetDetach(GetBoolArg("-detachdb", false));
-
#if !defined(WIN32) && !defined(QT_GUI)
fDaemon = GetBoolArg("-daemon");
#else
@@ -461,7 +540,7 @@ bool AppInit2()
if (file) fclose(file);
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock())
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), strDataDir.c_str()));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), strDataDir.c_str()));
#if !defined(WIN32) && !defined(QT_GUI)
if (fDaemon)
@@ -604,32 +683,28 @@ bool AppInit2()
#endif
bool fBound = false;
- if (!fNoListen)
- {
- std::string strError;
+ if (!fNoListen) {
if (mapArgs.count("-bind")) {
BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind.c_str()));
- fBound |= Bind(addrBind);
+ fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
- } else {
+ }
+ else {
struct in_addr inaddr_any;
inaddr_any.s_addr = INADDR_ANY;
#ifdef USE_IPV6
- if (!IsLimited(NET_IPV6))
- fBound |= Bind(CService(in6addr_any, GetListenPort()), false);
+ fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
#endif
- if (!IsLimited(NET_IPV4))
- fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound);
+ fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
}
if (!fBound)
return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
}
- if (mapArgs.count("-externalip"))
- {
+ if (mapArgs.count("-externalip")) {
BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
@@ -643,6 +718,8 @@ bool AppInit2()
// ********************************************************* Step 7: load block chain
+ fReindex = GetBoolArg("-reindex");
+
if (!bitdb.Open(GetDataDir()))
{
string msg = strprintf(_("Error initializing database environment %s!"
@@ -651,13 +728,28 @@ bool AppInit2()
return InitError(msg);
}
+ // cache size calculations
+ size_t nTotalCache = GetArg("-dbcache", 25) << 20;
+ if (nTotalCache < (1 << 22))
+ nTotalCache = (1 << 22); // total cache cannot be less than 4 MiB
+ size_t nBlockTreeDBCache = nTotalCache / 8;
+ if (nBlockTreeDBCache > (1 << 21))
+ nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
+ nTotalCache -= nBlockTreeDBCache;
+ size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache
+ nTotalCache -= nCoinDBCache;
+ nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes
+
uiInterface.InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
- pblocktree = new CBlockTreeDB();
- pcoinsdbview = new CCoinsViewDB();
+ pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+ if (fReindex)
+ pblocktree->WriteReindexing(true);
+
if (!LoadBlockIndex())
return InitError(_("Error loading blkindex.dat"));
@@ -790,13 +882,13 @@ bool AppInit2()
if (!ConnectBestBlock())
strErrors << "Failed to connect best block";
- std::vector<boost::filesystem::path> *vPath = new std::vector<boost::filesystem::path>();
+ CImportData *pimport = new CImportData();
if (mapArgs.count("-loadblock"))
{
BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
- vPath->push_back(strFile);
+ pimport->vFiles.push_back(strFile);
}
- NewThread(ThreadImport, vPath);
+ NewThread(ThreadImport, pimport);
// ********************************************************* Step 10: load peers
diff --git a/src/leveldb.cpp b/src/leveldb.cpp
index e8a0fbe874..9e2f32a171 100644
--- a/src/leveldb.cpp
+++ b/src/leveldb.cpp
@@ -12,27 +12,31 @@
#include <boost/filesystem.hpp>
-static leveldb::Options GetOptions() {
+static leveldb::Options GetOptions(size_t nCacheSize) {
leveldb::Options options;
- int nCacheSizeMB = GetArg("-dbcache", 25);
- options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576);
+ options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
+ options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
options.compression = leveldb::kNoCompression;
return options;
}
-CLevelDB::CLevelDB(const boost::filesystem::path &path, bool fMemory) {
+CLevelDB::CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory, bool fWipe) {
penv = NULL;
readoptions.verify_checksums = true;
iteroptions.verify_checksums = true;
iteroptions.fill_cache = false;
syncoptions.sync = true;
- options = GetOptions();
+ options = GetOptions(nCacheSize);
options.create_if_missing = true;
if (fMemory) {
penv = leveldb::NewMemEnv(leveldb::Env::Default());
options.env = penv;
} else {
+ if (fWipe) {
+ printf("Wiping LevelDB in %s\n", path.string().c_str());
+ leveldb::DestroyDB(path.string(), options);
+ }
boost::filesystem::create_directory(path);
printf("Opening LevelDB in %s\n", path.string().c_str());
}
diff --git a/src/leveldb.h b/src/leveldb.h
index ee9079c3c3..0b83432072 100644
--- a/src/leveldb.h
+++ b/src/leveldb.h
@@ -69,7 +69,7 @@ private:
leveldb::DB *pdb;
public:
- CLevelDB(const boost::filesystem::path &path, bool fMemory = false);
+ CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
~CLevelDB();
template<typename K, typename V> bool Read(const K& key, V& value) {
diff --git a/src/leveldb/Makefile b/src/leveldb/Makefile
index 7f658cfdf9..14e494f3ce 100755
--- a/src/leveldb/Makefile
+++ b/src/leveldb/Makefile
@@ -19,10 +19,10 @@ $(shell ./build_detect_platform build_config.mk)
# this file is generated by the previous line to set build flags and sources
include build_config.mk
-CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT)
-CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT)
+xCFLAGS = -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) $(CFLAGS)
+xCXXFLAGS = -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) $(CXXFLAGS)
-LDFLAGS += $(PLATFORM_LDFLAGS)
+xLDFLAGS = $(PLATFORM_LDFLAGS) $(LDFLAGS)
LIBOBJECTS = $(SOURCES:.cc=.o)
MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o)
@@ -82,7 +82,7 @@ $(SHARED2): $(SHARED3)
endif
$(SHARED3):
- $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) $(PLATFORM_EXTRALIBS) -o $(SHARED3)
+ $(CXX) $(xLDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(xCXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) $(PLATFORM_EXTRALIBS) -o $(SHARED3)
endif # PLATFORM_SHARED_EXT
@@ -100,74 +100,74 @@ $(LIBRARY): $(LIBOBJECTS)
$(AR) -rs $@ $(LIBOBJECTS)
db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL)
- $(CXX) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL)
- $(CXX) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) -lsqlite3
+ $(CXX) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) -lsqlite3
db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL)
- $(CXX) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) -lkyotocabinet
+ $(CXX) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) -lkyotocabinet
arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS)
- $(CXX) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
$(MEMENVLIBRARY) : $(MEMENVOBJECTS)
rm -f $@
$(AR) -rs $@ $(MEMENVOBJECTS)
memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS)
- $(CXX) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS)
+ $(CXX) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS)
ifeq ($(PLATFORM), IOS)
# For iOS, create universal object files to be used on both the simulator and
@@ -179,22 +179,22 @@ IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBu
.cc.o:
mkdir -p ios-x86/$(dir $@)
- $(SIMULATORROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
+ $(SIMULATORROOT)/usr/bin/$(CXX) $(xCXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
mkdir -p ios-arm/$(dir $@)
- $(DEVICEROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@
+ $(DEVICEROOT)/usr/bin/$(CXX) $(xCXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@
lipo ios-x86/$@ ios-arm/$@ -create -output $@
.c.o:
mkdir -p ios-x86/$(dir $@)
- $(SIMULATORROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
+ $(SIMULATORROOT)/usr/bin/$(CC) $(xCFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@
mkdir -p ios-arm/$(dir $@)
- $(DEVICEROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@
+ $(DEVICEROOT)/usr/bin/$(CC) $(xCFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@
lipo ios-x86/$@ ios-arm/$@ -create -output $@
else
.cc.o:
- $(CXX) $(CXXFLAGS) -c $< -o $@
+ $(CXX) $(xCXXFLAGS) -c $< -o $@
.c.o:
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(xCFLAGS) -c $< -o $@
endif
diff --git a/src/main.cpp b/src/main.cpp
index 43bd5dd472..f0bf4755b7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -41,6 +41,8 @@ CBlockIndex* pindexBest = NULL;
set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed
int64 nTimeBestReceived = 0;
bool fImporting = false;
+bool fReindex = false;
+unsigned int nCoinCacheSize = 5000;
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
@@ -1144,7 +1146,7 @@ int GetNumBlocksOfPeers()
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
+ if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate() || fReindex || fImporting)
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
@@ -1735,7 +1737,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload();
- if (!fIsInitialDownload || view.GetCacheSize()>5000) {
+ if (!fIsInitialDownload || view.GetCacheSize() > nCoinCacheSize) {
FlushBlockFile();
pblocktree->Sync();
if (!view.Flush())
@@ -1861,35 +1863,45 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
}
-bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime)
+bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime, bool fKnown = false)
{
bool fUpdatedLast = false;
LOCK(cs_LastBlockFile);
- while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
- printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
- FlushBlockFile();
- nLastBlockFile++;
- infoLastBlockFile.SetNull();
- pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine
- fUpdatedLast = true;
+ if (fKnown) {
+ if (nLastBlockFile != pos.nFile) {
+ nLastBlockFile = pos.nFile;
+ infoLastBlockFile.SetNull();
+ pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile);
+ }
+ } else {
+ while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
+ printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
+ FlushBlockFile();
+ nLastBlockFile++;
+ infoLastBlockFile.SetNull();
+ pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine
+ fUpdatedLast = true;
+ }
+ pos.nFile = nLastBlockFile;
+ pos.nPos = infoLastBlockFile.nSize;
}
- pos.nFile = nLastBlockFile;
- pos.nPos = infoLastBlockFile.nSize;
infoLastBlockFile.nSize += nAddSize;
infoLastBlockFile.AddBlock(nHeight, nTime);
- unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
- unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
- if (nNewChunks > nOldChunks) {
- FILE *file = OpenBlockFile(pos);
- if (file) {
- printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
- AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos);
+ if (!fKnown) {
+ unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
+ unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
+ if (nNewChunks > nOldChunks) {
+ FILE *file = OpenBlockFile(pos);
+ if (file) {
+ printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
+ AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos);
+ }
+ fclose(file);
}
- fclose(file);
}
if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile))
@@ -1995,7 +2007,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
return true;
}
-bool CBlock::AcceptBlock()
+bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
{
// Check for duplicate
uint256 hash = GetHash();
@@ -2003,60 +2015,69 @@ bool CBlock::AcceptBlock()
return error("AcceptBlock() : block already in mapBlockIndex");
// Get prev block index
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
- if (mi == mapBlockIndex.end())
- return DoS(10, error("AcceptBlock() : prev block not found"));
- CBlockIndex* pindexPrev = (*mi).second;
- int nHeight = pindexPrev->nHeight+1;
-
- // Check proof of work
- if (nBits != GetNextWorkRequired(pindexPrev, this))
- return DoS(100, error("AcceptBlock() : incorrect proof of work"));
-
- // Check timestamp against prev
- if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
- return error("AcceptBlock() : block's timestamp is too early");
-
- // Check that all transactions are finalized
- BOOST_FOREACH(const CTransaction& tx, vtx)
- if (!tx.IsFinal(nHeight, GetBlockTime()))
- return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
-
- // Check that the block chain matches the known block chain up to a checkpoint
- if (!Checkpoints::CheckBlock(nHeight, hash))
- return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
-
- // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
- if (nVersion < 2)
- {
- if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
- (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
+ CBlockIndex* pindexPrev = NULL;
+ int nHeight = 0;
+ if (hash != hashGenesisBlock) {
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
+ if (mi == mapBlockIndex.end())
+ return DoS(10, error("AcceptBlock() : prev block not found"));
+ pindexPrev = (*mi).second;
+ nHeight = pindexPrev->nHeight+1;
+
+ // Check proof of work
+ if (nBits != GetNextWorkRequired(pindexPrev, this))
+ return DoS(100, error("AcceptBlock() : incorrect proof of work"));
+
+ // Check timestamp against prev
+ if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
+ return error("AcceptBlock() : block's timestamp is too early");
+
+ // Check that all transactions are finalized
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ if (!tx.IsFinal(nHeight, GetBlockTime()))
+ return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
+
+ // Check that the block chain matches the known block chain up to a checkpoint
+ if (!Checkpoints::CheckBlock(nHeight, hash))
+ return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
+
+ // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
+ if (nVersion < 2)
{
- return error("AcceptBlock() : rejected nVersion=1 block");
+ if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
+ (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
+ {
+ return error("AcceptBlock() : rejected nVersion=1 block");
+ }
}
- }
- // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
- if (nVersion >= 2)
- {
- // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
- if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
- (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
+ // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
+ if (nVersion >= 2)
{
- CScript expect = CScript() << nHeight;
- if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
- return DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
+ // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
+ if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
+ (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
+ {
+ CScript expect = CScript() << nHeight;
+ if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
+ return DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
+ }
}
}
// Write block to history file
unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
- if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
- return error("AcceptBlock() : out of disk space");
CDiskBlockPos blockPos;
- if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime))
+ if (dbp == NULL) {
+ if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
+ return error("AcceptBlock() : out of disk space");
+ } else {
+ blockPos = *dbp;
+ }
+ if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
return error("AcceptBlock() : FindBlockPos failed");
- if (!WriteToDisk(blockPos))
- return error("AcceptBlock() : WriteToDisk failed");
+ if (dbp == NULL)
+ if (!WriteToDisk(blockPos))
+ return error("AcceptBlock() : WriteToDisk failed");
if (!AddToBlockIndex(blockPos))
return error("AcceptBlock() : AddToBlockIndex failed");
@@ -2085,7 +2106,7 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
-bool ProcessBlock(CNode* pfrom, CBlock* pblock)
+bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
@@ -2123,7 +2144,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// If we don't already have its previous block, shunt it off to holding area until we get it
- if (!mapBlockIndex.count(pblock->hashPrevBlock))
+ if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock))
{
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
@@ -2140,7 +2161,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
}
// Store to disk
- if (!pblock->AcceptBlock())
+ if (!pblock->AcceptBlock(dbp))
return error("ProcessBlock() : AcceptBlock FAILED");
// Recursively process any orphan blocks that depended on this one
@@ -2303,6 +2324,11 @@ bool static LoadBlockIndexDB()
// Load bnBestInvalidWork, OK if it doesn't exist
pblocktree->ReadBestInvalidWork(bnBestInvalidWork);
+ // Check whether we need to continue reindexing
+ bool fReindexing = false;
+ pblocktree->ReadReindexing(fReindexing);
+ fReindex |= fReindexing;
+
// Verify blocks in the best chain
int nCheckLevel = GetArg("-checklevel", 1);
int nCheckDepth = GetArg( "-checkblocks", 2500);
@@ -2336,7 +2362,7 @@ bool static LoadBlockIndexDB()
return true;
}
-bool LoadBlockIndex(bool fAllowNew)
+bool LoadBlockIndex()
{
if (fTestNet)
{
@@ -2347,6 +2373,9 @@ bool LoadBlockIndex(bool fAllowNew)
hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
}
+ if (fReindex)
+ return true;
+
//
// Load block index from databases
//
@@ -2358,9 +2387,6 @@ bool LoadBlockIndex(bool fAllowNew)
//
if (mapBlockIndex.empty())
{
- if (!fAllowNew)
- return false;
-
// Genesis Block:
// CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
// CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
@@ -2486,110 +2512,71 @@ void PrintBlockTree()
}
}
-bool LoadExternalBlockFile(FILE* fileIn)
+bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
{
int64 nStart = GetTimeMillis();
int nLoaded = 0;
{
- try {
- CAutoFile blkdat(fileIn, SER_DISK, CLIENT_VERSION);
- unsigned int nPos = 0;
- while (nPos != (unsigned int)-1 && blkdat.good() && !fRequestShutdown)
- {
- unsigned char pchData[65536];
- do {
- fseek(blkdat, nPos, SEEK_SET);
- int nRead = fread(pchData, 1, sizeof(pchData), blkdat);
- if (nRead <= 8)
- {
- nPos = (unsigned int)-1;
- break;
- }
- void* nFind = memchr(pchData, pchMessageStart[0], nRead+1-sizeof(pchMessageStart));
- if (nFind)
- {
- if (memcmp(nFind, pchMessageStart, sizeof(pchMessageStart))==0)
- {
- nPos += ((unsigned char*)nFind - pchData) + sizeof(pchMessageStart);
- break;
- }
- nPos += ((unsigned char*)nFind - pchData) + 1;
- }
- else
- nPos += sizeof(pchData) - sizeof(pchMessageStart) + 1;
- } while(!fRequestShutdown);
- if (nPos == (unsigned int)-1)
- break;
- fseek(blkdat, nPos, SEEK_SET);
- unsigned int nSize;
+ CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION);
+ uint64 nStartByte = 0;
+ if (dbp) {
+ // (try to) skip already indexed part
+ CBlockFileInfo info;
+ if (pblocktree->ReadBlockFileInfo(dbp->nFile, info)) {
+ nStartByte = info.nSize;
+ blkdat.Seek(info.nSize);
+ }
+ }
+ uint64 nRewind = blkdat.GetPos();
+ while (blkdat.good() && !blkdat.eof() && !fShutdown) {
+ blkdat.SetPos(nRewind);
+ nRewind++; // start one byte further next time, in case of failure
+ blkdat.SetLimit(); // remove former limit
+ unsigned int nSize = 0;
+ try {
+ // locate a header
+ unsigned char buf[4];
+ blkdat.FindByte(pchMessageStart[0]);
+ nRewind = blkdat.GetPos()+1;
+ blkdat >> FLATDATA(buf);
+ if (memcmp(buf, pchMessageStart, 4))
+ continue;
+ // read size
blkdat >> nSize;
- if (nSize > 0 && nSize <= MAX_BLOCK_SIZE)
- {
- CBlock block;
- blkdat >> block;
+ if (nSize < 80 || nSize > MAX_BLOCK_SIZE)
+ continue;
+ } catch (std::exception &e) {
+ // no valid block header found; don't complain
+ break;
+ }
+ try {
+ // read block
+ uint64 nBlockPos = blkdat.GetPos();
+ blkdat.SetLimit(nBlockPos + nSize);
+ CBlock block;
+ blkdat >> block;
+ nRewind = blkdat.GetPos();
+
+ // process block
+ if (nBlockPos >= nStartByte) {
LOCK(cs_main);
- if (ProcessBlock(NULL,&block))
- {
+ if (dbp)
+ dbp->nPos = nBlockPos;
+ if (ProcessBlock(NULL, &block, dbp))
nLoaded++;
- nPos += 4 + nSize;
- }
}
+ } catch (std::exception &e) {
+ printf("%s() : Deserialize or I/O error caught during load\n", __PRETTY_FUNCTION__);
}
}
- catch (std::exception &e) {
- printf("%s() : Deserialize or I/O error caught during load\n",
- __PRETTY_FUNCTION__);
- }
+ fclose(fileIn);
}
- printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart);
+ if (nLoaded > 0)
+ printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart);
return nLoaded > 0;
}
-struct CImportingNow
-{
- CImportingNow() {
- assert(fImporting == false);
- fImporting = true;
- }
-
- ~CImportingNow() {
- assert(fImporting == true);
- fImporting = false;
- }
-};
-
-void ThreadImport(void *data) {
- std::vector<boost::filesystem::path> *vFiles = reinterpret_cast<std::vector<boost::filesystem::path>*>(data);
-
- RenameThread("bitcoin-loadblk");
-
- CImportingNow imp;
- vnThreadsRunning[THREAD_IMPORT]++;
-
- // -loadblock=
- BOOST_FOREACH(boost::filesystem::path &path, *vFiles) {
- FILE *file = fopen(path.string().c_str(), "rb");
- if (file)
- LoadExternalBlockFile(file);
- }
-
- // hardcoded $DATADIR/bootstrap.dat
- filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
- if (filesystem::exists(pathBootstrap)) {
- FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
- if (file) {
- filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
- LoadExternalBlockFile(file);
- RenameOver(pathBootstrap, pathBootstrapOld);
- }
- }
-
- delete vFiles;
-
- vnThreadsRunning[THREAD_IMPORT]--;
-}
-
@@ -2799,7 +2786,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Ask the first connected node for block updates
static int nAskedForBlocks = 0;
- if (!pfrom->fClient && !pfrom->fOneShot && !fImporting &&
+ if (!pfrom->fClient && !pfrom->fOneShot && !fImporting && !fReindex &&
(pfrom->nStartingHeight > (nBestHeight - 144)) &&
(pfrom->nVersion < NOBLKS_VERSION_START ||
pfrom->nVersion >= NOBLKS_VERSION_END) &&
@@ -2936,7 +2923,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
if (!fAlreadyHave) {
- if (!fImporting)
+ if (!fImporting && !fReindex)
pfrom->AskFor(inv);
} else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
@@ -3166,7 +3153,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
- else if (strCommand == "block")
+ else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing
{
CBlock block;
vRecv >> block;
diff --git a/src/main.h b/src/main.h
index 744c0e4b51..0ef192f901 100644
--- a/src/main.h
+++ b/src/main.h
@@ -22,7 +22,7 @@ class CAddress;
class CInv;
class CNode;
-class CBlockIndexWorkComparator;
+struct CBlockIndexWorkComparator;
/** The maximum allowed size for a serialized block, in bytes (network rule) */
static const unsigned int MAX_BLOCK_SIZE = 1000000;
@@ -88,6 +88,8 @@ extern CCriticalSection cs_setpwalletRegistered;
extern std::set<CWallet*> setpwalletRegistered;
extern unsigned char pchMessageStart[4];
extern bool fImporting;
+extern bool fReindex;
+extern unsigned int nCoinCacheSize;
// Settings
extern int64 nTransactionFee;
@@ -105,32 +107,61 @@ class CTxUndo;
class CCoinsView;
class CCoinsViewCache;
+/** Register a wallet to receive updates from core */
void RegisterWallet(CWallet* pwalletIn);
+/** Unregister a wallet from core */
void UnregisterWallet(CWallet* pwalletIn);
+/** Push an updated transaction to all registered wallets */
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
-bool ProcessBlock(CNode* pfrom, CBlock* pblock);
+/** Process an incoming block */
+bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
+/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
+/** Open a block file (blk?????.dat) */
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
+/** Open an undo file (rev?????.dat) */
FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
-bool LoadBlockIndex(bool fAllowNew=true);
+/** Import blocks from an external file */
+bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
+/** Load the block tree and coins database from disk */
+bool LoadBlockIndex();
+/** Print the loaded block tree */
void PrintBlockTree();
+/** Find a block by height in the currently-connected chain */
CBlockIndex* FindBlockByHeight(int nHeight);
+/** Process protocol messages received from a given node */
bool ProcessMessages(CNode* pfrom);
+/** Send queued protocol messages to be sent to a give node */
bool SendMessages(CNode* pto, bool fSendTrickle);
+/** Run the importer thread, which deals with reindexing, loading bootstrap.dat, and whatever is passed to -loadblock */
void ThreadImport(void *parg);
+/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
+/** Generate a new block, without valid proof-of-work */
CBlock* CreateNewBlock(CReserveKey& reservekey);
+/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
+/** Do mining precalculation */
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
+/** Check mined block */
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
+/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
+/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
+/** Get the number of active peers */
int GetNumBlocksOfPeers();
+/** Check whether we are doin an inital block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
+/** Format a string that describes several potential problems detected by the core */
std::string GetWarnings(std::string strFor);
+/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
+/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */
bool SetBestChain(CBlockIndex* pindexNew);
+/** Find the best known block, and make it the tip of the block chain */
bool ConnectBestBlock();
+/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
@@ -1260,7 +1291,8 @@ public:
bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const;
// Store block on disk
- bool AcceptBlock();
+ // if dbp is provided, the file is known to already reside on disk
+ bool AcceptBlock(CDiskBlockPos *dbp = NULL);
};
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 7b28e7f1bc..9e7307204a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -545,7 +545,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
void CNetAddr::Init()
{
- memset(ip, 0, 16);
+ memset(ip, 0, sizeof(ip));
}
void CNetAddr::SetIP(const CNetAddr& ipIn)
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index df87486949..f7d177c513 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -82,4 +82,4 @@ signals:
void verifyMessage(QString addr);
};
-#endif // ADDRESSBOOKDIALOG_H
+#endif // ADDRESSBOOKPAGE_H
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index 66792e00a9..4797c4c882 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -1,5 +1,5 @@
-#ifndef BITCOINFIELD_H
-#define BITCOINFIELD_H
+#ifndef BITCOINAMOUNTFIELD_H
+#define BITCOINAMOUNTFIELD_H
#include <QWidget>
@@ -57,4 +57,4 @@ private slots:
};
-#endif // BITCOINFIELD_H
+#endif // BITCOINAMOUNTFIELD_H
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index c09e1ce447..0198a92c05 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -489,7 +489,8 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
statusBar()->clearMessage();
// don't show / hide progress bar and its label if we have no connection to the network
- if (!clientModel || (clientModel->getNumConnections() == 0 && !clientModel->isImporting()))
+ enum BlockSource blockSource = clientModel ? clientModel->getBlockSource() : BLOCK_SOURCE_NONE;
+ if (blockSource == BLOCK_SOURCE_NONE || (blockSource == BLOCK_SOURCE_NETWORK && clientModel->getNumConnections() == 0))
{
progressBarLabel->setVisible(false);
progressBar->setVisible(false);
@@ -499,26 +500,39 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
QString tooltip;
+ QString importText;
+ switch (blockSource) {
+ case BLOCK_SOURCE_NONE:
+ case BLOCK_SOURCE_NETWORK:
+ importText = tr("Synchronizing with network...");
+ break;
+ case BLOCK_SOURCE_DISK:
+ importText = tr("Importing blocks from disk...");
+ break;
+ case BLOCK_SOURCE_REINDEX:
+ importText = tr("Reindexing blocks on disk...");
+ }
+
if(count < nTotalBlocks)
{
int nRemainingBlocks = nTotalBlocks - count;
float nPercentageDone = count / (nTotalBlocks * 0.01f);
- progressBarLabel->setText(tr(clientModel->isImporting() ? "Importing blocks..." : "Synchronizing with network..."));
+ progressBarLabel->setText(importText);
progressBarLabel->setVisible(true);
progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
progressBar->setMaximum(nTotalBlocks);
progressBar->setValue(count);
progressBar->setVisible(true);
- tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
+ tooltip = tr("Processed %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
}
else
{
progressBarLabel->setVisible(false);
progressBar->setVisible(false);
- tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
+ tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
}
QDateTime lastBlockDate = clientModel->getLastBlockDate();
@@ -625,11 +639,9 @@ void BitcoinGUI::closeEvent(QCloseEvent *event)
void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
{
- QString strMessage =
- tr("This transaction is over the size limit. You can still send it for a fee of %1, "
- "which goes to the nodes that process your transaction and helps to support the network. "
- "Do you want to pay the fee?").arg(
- BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
+ QString strMessage = tr("This transaction is over the size limit. You can still send it for a fee of %1, "
+ "which goes to the nodes that process your transaction and helps to support the network. "
+ "Do you want to pay the fee?").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nFeeRequired));
QMessageBox::StandardButton retval = QMessageBox::question(
this, tr("Confirm transaction fee"), strMessage,
QMessageBox::Yes|QMessageBox::Cancel, QMessageBox::Yes);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index a48911ee7f..8b4607d3ed 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -177,4 +177,4 @@ private slots:
void toggleHidden();
};
-#endif
+#endif // BITCOINGUI_H
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index b92a26c4a4..7e8e102ee7 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -27,8 +27,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
"running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Detach block and address databases. Increases shutdown time (default: 0)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"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."),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 25db695a0b..9b7362d757 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -101,9 +101,13 @@ bool ClientModel::inInitialBlockDownload() const
return IsInitialBlockDownload();
}
-bool ClientModel::isImporting() const
+enum BlockSource ClientModel::getBlockSource() const
{
- return fImporting;
+ if (fReindex)
+ return BLOCK_SOURCE_REINDEX;
+ if (fImporting)
+ return BLOCK_SOURCE_DISK;
+ return BLOCK_SOURCE_NETWORK;
}
int ClientModel::getNumBlocksOfPeers() const
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index fd0135b3e6..7d6401ab25 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -13,6 +13,13 @@ class QDateTime;
class QTimer;
QT_END_NAMESPACE
+enum BlockSource {
+ BLOCK_SOURCE_NONE,
+ BLOCK_SOURCE_NETWORK,
+ BLOCK_SOURCE_DISK,
+ BLOCK_SOURCE_REINDEX
+};
+
/** Model for Bitcoin network client. */
class ClientModel : public QObject
{
@@ -34,7 +41,7 @@ public:
//! Return true if core is doing initial block download
bool inInitialBlockDownload() const;
//! Return true if core is importing blocks
- bool isImporting() const;
+ enum BlockSource getBlockSource() const;
//! Return conservative estimate of total number of blocks, or 0 if unknown
int getNumBlocksOfPeers() const;
//! Return warnings to be displayed in status bar
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 1b81b0cdc8..6a13361974 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -87,16 +87,6 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="detachDatabases">
- <property name="toolTip">
- <string>Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached.</string>
- </property>
- <property name="text">
- <string>&amp;Detach databases at shutdown</string>
- </property>
- </widget>
- </item>
- <item>
<spacer name="verticalSpacer_Main">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index 22a3f8fdc6..28553c5508 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -52,23 +52,6 @@
<item row="5" column="1">
<widget class="BitcoinAmountField" name="payAmount"/>
</item>
- <item row="4" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <property name="spacing">
- <number>0</number>
- </property>
- <item>
- <widget class="QValidatedLineEdit" name="addAsLabel">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="toolTip">
- <string>Enter a label for this address to add it to your address book</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
@@ -90,7 +73,7 @@
<item>
<widget class="QValidatedLineEdit" name="payTo">
<property name="toolTip">
- <string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
+ <string>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</string>
</property>
<property name="maxLength">
<number>34</number>
@@ -147,6 +130,13 @@
</item>
</layout>
</item>
+ <item row="4" column="1">
+ <widget class="QValidatedLineEdit" name="addAsLabel">
+ <property name="toolTip">
+ <string>Enter a label for this address to add it to your address book</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<customwidgets>
diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h
index 2092fb26b3..dd85e0c33d 100644
--- a/src/qt/macdockiconhandler.h
+++ b/src/qt/macdockiconhandler.h
@@ -1,7 +1,7 @@
#ifndef MACDOCKICONHANDLER_H
#define MACDOCKICONHANDLER_H
-#include <QtCore/QObject>
+#include <QObject>
class QMenu;
class QIcon;
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 3fb30a9518..03dcb0b538 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -128,7 +128,6 @@ void OptionsDialog::setMapper()
/* Main */
mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
- mapper->addMapping(ui->detachDatabases, OptionsModel::DetachDatabases);
/* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 1075ce1e6c..e3c9413f1b 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -56,8 +56,6 @@ void OptionsModel::Init()
SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool())
SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString());
- if (settings.contains("detachDB"))
- SoftSetBoolArg("-detachdb", settings.value("detachDB").toBool());
if (!language.isEmpty())
SoftSetArg("-lang", language.toStdString());
}
@@ -173,8 +171,6 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return QVariant(nDisplayUnit);
case DisplayAddresses:
return QVariant(bDisplayAddresses);
- case DetachDatabases:
- return QVariant(bitdb.GetDetach());
case Language:
return settings.value("language", "");
default:
@@ -256,12 +252,6 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
bDisplayAddresses = value.toBool();
settings.setValue("bDisplayAddresses", bDisplayAddresses);
break;
- case DetachDatabases: {
- bool fDetachDB = value.toBool();
- bitdb.SetDetach(fDetachDB);
- settings.setValue("detachDB", fDetachDB);
- }
- break;
case Language:
settings.setValue("language", value);
break;
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 2d86a7a9ca..4f893bb44e 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -28,7 +28,6 @@ public:
Fee, // qint64
DisplayUnit, // BitcoinUnits::Unit
DisplayAddresses, // bool
- DetachDatabases, // bool
Language, // QString
OptionIDRowCount,
};
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index ca2c615333..0c1547bd8e 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -148,7 +148,7 @@ void SendCoinsDialog::on_sendButton_clicked()
break;
case WalletModel::TransactionCreationFailed:
QMessageBox::warning(this, tr("Send Coins"),
- tr("Error: Transaction creation failed."),
+ tr("Error: Transaction creation failed!"),
QMessageBox::Ok, QMessageBox::Ok);
break;
case WalletModel::TransactionCommitFailed:
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index fd321ce280..b0687d5399 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -81,5 +81,4 @@ public slots:
friend class TransactionTablePriv;
};
-#endif
-
+#endif // TRANSACTIONTABLEMODEL_H
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index cd91f650a8..29b3298b99 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -1429,7 +1429,7 @@ Value encryptwallet(const Array& params, bool fHelp)
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
StartShutdown();
- return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
+ return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
}
class DescribeAddressVisitor : public boost::static_visitor<Object>
diff --git a/src/serialize.h b/src/serialize.h
index 549e46cbc3..9e14666fac 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1225,4 +1225,148 @@ public:
}
};
+/** Wrapper around a FILE* that implements a ring buffer to
+ * deserialize from. It guarantees the ability to rewind
+ * a given number of bytes. */
+class CBufferedFile
+{
+private:
+ FILE *src; // source file
+ uint64 nSrcPos; // how many bytes have been read from source
+ uint64 nReadPos; // how many bytes have been read from this
+ uint64 nReadLimit; // up to which position we're allowed to read
+ uint64 nRewind; // how many bytes we guarantee to rewind
+ std::vector<char> vchBuf; // the buffer
+
+ short state;
+ short exceptmask;
+
+protected:
+ void setstate(short bits, const char *psz) {
+ state |= bits;
+ if (state & exceptmask)
+ throw std::ios_base::failure(psz);
+ }
+
+ // read data from the source to fill the buffer
+ bool Fill() {
+ unsigned int pos = nSrcPos % vchBuf.size();
+ unsigned int readNow = vchBuf.size() - pos;
+ unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
+ if (nAvail < readNow)
+ readNow = nAvail;
+ if (readNow == 0)
+ return false;
+ size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
+ if (read == 0) {
+ setstate(std::ios_base::failbit, feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed");
+ return false;
+ } else {
+ nSrcPos += read;
+ return true;
+ }
+ }
+
+public:
+ int nType;
+ int nVersion;
+
+ CBufferedFile(FILE *fileIn, uint64 nBufSize, uint64 nRewindIn, int nTypeIn, int nVersionIn) :
+ src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0),
+ state(0), exceptmask(std::ios_base::badbit | std::ios_base::failbit), nType(nTypeIn), nVersion(nVersionIn) {
+ }
+
+ // check whether no error occurred
+ bool good() const {
+ return state == 0;
+ }
+
+ // check whether we're at the end of the source file
+ bool eof() const {
+ return nReadPos == nSrcPos && feof(src);
+ }
+
+ // read a number of bytes
+ CBufferedFile& read(char *pch, size_t nSize) {
+ if (nSize + nReadPos > nReadLimit)
+ throw std::ios_base::failure("Read attempted past buffer limit");
+ if (nSize + nRewind > vchBuf.size())
+ throw std::ios_base::failure("Read larger than buffer size");
+ while (nSize > 0) {
+ if (nReadPos == nSrcPos)
+ Fill();
+ unsigned int pos = nReadPos % vchBuf.size();
+ size_t nNow = nSize;
+ if (nNow + pos > vchBuf.size())
+ nNow = vchBuf.size() - pos;
+ if (nNow + nReadPos > nSrcPos)
+ nNow = nSrcPos - nReadPos;
+ memcpy(pch, &vchBuf[pos], nNow);
+ nReadPos += nNow;
+ pch += nNow;
+ nSize -= nNow;
+ }
+ return (*this);
+ }
+
+ // return the current reading position
+ uint64 GetPos() {
+ return nReadPos;
+ }
+
+ // rewind to a given reading position
+ bool SetPos(uint64 nPos) {
+ nReadPos = nPos;
+ if (nReadPos + nRewind < nSrcPos) {
+ nReadPos = nSrcPos - nRewind;
+ return false;
+ } else if (nReadPos > nSrcPos) {
+ nReadPos = nSrcPos;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ bool Seek(uint64 nPos) {
+ long nLongPos = nPos;
+ if (nPos != (uint64)nLongPos)
+ return false;
+ if (fseek(src, nLongPos, SEEK_SET))
+ return false;
+ nLongPos = ftell(src);
+ nSrcPos = nLongPos;
+ nReadPos = nLongPos;
+ state = 0;
+ return true;
+ }
+
+ // prevent reading beyond a certain position
+ // no argument removes the limit
+ bool SetLimit(uint64 nPos = (uint64)(-1)) {
+ if (nPos < nReadPos)
+ return false;
+ nReadLimit = nPos;
+ return true;
+ }
+
+ template<typename T>
+ CBufferedFile& operator>>(T& obj) {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+
+ // search for a given byte in the stream, and remain positioned on it
+ void FindByte(char ch) {
+ while (true) {
+ if (nReadPos == nSrcPos)
+ Fill();
+ if (vchBuf[nReadPos % vchBuf.size()] == ch)
+ break;
+ nReadPos++;
+ }
+ }
+};
+
#endif
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index c1f47f786b..e4ba0259ba 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -19,10 +19,10 @@ struct TestingSetup {
fPrintToDebugger = true; // don't want to write to debug.log file
noui_connect();
bitdb.MakeMock();
- pblocktree = new CBlockTreeDB(true);
- pcoinsdbview = new CCoinsViewDB(true);
+ pblocktree = new CBlockTreeDB(1 << 20, true);
+ pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
- LoadBlockIndex(true);
+ LoadBlockIndex();
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
pwalletMain->LoadWallet(fFirstRun);
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 6550f57876..93c5f23d8b 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -19,7 +19,7 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
batch.Write('B', hash);
}
-CCoinsViewDB::CCoinsViewDB(bool fMemory) : db(GetDataDir() / "coins", fMemory) {
+CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "coins", nCacheSize, fMemory, fWipe) {
}
bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
@@ -64,7 +64,7 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockI
return db.WriteBatch(batch);
}
-CBlockTreeDB::CBlockTreeDB(bool fMemory) : CLevelDB(GetDataDir() / "blktree", fMemory) {
+CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blktree", nCacheSize, fMemory, fWipe) {
}
bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
@@ -94,6 +94,18 @@ bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
return Write('l', nFile);
}
+bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
+ if (fReindexing)
+ return Write('R', '1');
+ else
+ return Erase('R');
+}
+
+bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
+ fReindexing = Exists('R');
+ return true;
+}
+
bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
return Read('l', nFile);
}
diff --git a/src/txdb.h b/src/txdb.h
index 123ec00d23..d7d327069f 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -14,7 +14,7 @@ class CCoinsViewDB : public CCoinsView
protected:
CLevelDB db;
public:
- CCoinsViewDB(bool fMemory = false);
+ CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoins(uint256 txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins);
@@ -29,7 +29,7 @@ public:
class CBlockTreeDB : public CLevelDB
{
public:
- CBlockTreeDB(bool fMemory = false);
+ CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
private:
CBlockTreeDB(const CBlockTreeDB&);
void operator=(const CBlockTreeDB&);
@@ -41,6 +41,8 @@ public:
bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
bool ReadLastBlockFile(int &nFile);
bool WriteLastBlockFile(int nFile);
+ bool WriteReindexing(bool fReindex);
+ bool ReadReindexing(bool &fReindex);
bool LoadBlockIndexGuts();
};
diff --git a/src/util.cpp b/src/util.cpp
index 9162886450..03014a5da0 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -156,7 +156,7 @@ void RandAddSeedPerfmon()
if (ret == ERROR_SUCCESS)
{
RAND_add(pdata, nSize, nSize/100.0);
- memset(pdata, 0, nSize);
+ OPENSSL_cleanse(pdata, nSize);
printf("RandAddSeed() %lu bytes\n", nSize);
}
#endif
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 67b4e8f095..0115e56b8e 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -926,9 +926,8 @@ int64 CWallet::GetImmatureBalance() const
LOCK(cs_wallet);
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
- const CWalletTx& pcoin = (*it).second;
- if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.IsInMainChain())
- nTotal += GetCredit(pcoin);
+ const CWalletTx* pcoin = &(*it).second;
+ nTotal += pcoin->GetImmatureCredit();
}
}
return nTotal;
@@ -1292,7 +1291,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
if (IsLocked())
{
- string strError = _("Error: Wallet locked, unable to create transaction ");
+ string strError = _("Error: Wallet locked, unable to create transaction!");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
@@ -1300,9 +1299,9 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
{
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());
+ 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 ");
+ strError = _("Error: Transaction creation failed!");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
@@ -1311,7 +1310,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
- return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+ return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
return "";
}
diff --git a/src/wallet.h b/src/wallet.h
index 43b695c597..5e2f8e0ba1 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -375,10 +375,12 @@ public:
// memory only
mutable bool fDebitCached;
mutable bool fCreditCached;
+ mutable bool fImmatureCreditCached;
mutable bool fAvailableCreditCached;
mutable bool fChangeCached;
mutable int64 nDebitCached;
mutable int64 nCreditCached;
+ mutable int64 nImmatureCreditCached;
mutable int64 nAvailableCreditCached;
mutable int64 nChangeCached;
@@ -416,10 +418,12 @@ public:
vfSpent.clear();
fDebitCached = false;
fCreditCached = false;
+ fImmatureCreditCached = false;
fAvailableCreditCached = false;
fChangeCached = false;
nDebitCached = 0;
nCreditCached = 0;
+ nImmatureCreditCached = 0;
nAvailableCreditCached = 0;
nChangeCached = 0;
nOrderPos = -1;
@@ -563,6 +567,20 @@ public:
return nCreditCached;
}
+ int64 GetImmatureCredit(bool fUseCache=true) const
+ {
+ if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
+ {
+ if (fUseCache && fImmatureCreditCached)
+ return nImmatureCreditCached;
+ nImmatureCreditCached = pwallet->GetCredit(*this);
+ fImmatureCreditCached = true;
+ return nImmatureCreditCached;
+ }
+
+ return 0;
+ }
+
int64 GetAvailableCredit(bool fUseCache=true) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it