aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/allocators.h5
-rw-r--r--src/base58.h16
-rw-r--r--src/bitcoinrpc.cpp95
-rw-r--r--src/bitcoinrpc.h3
-rw-r--r--src/checkpoints.cpp9
-rw-r--r--src/clientversion.h3
-rw-r--r--src/crypter.cpp4
-rw-r--r--src/crypter.h4
-rw-r--r--src/db.cpp37
-rw-r--r--src/db.h9
-rw-r--r--src/init.cpp165
-rw-r--r--src/irc.cpp5
-rw-r--r--src/leveldb.cpp14
-rw-r--r--src/leveldb.h2
-rwxr-xr-xsrc/leveldb/Makefile64
-rw-r--r--src/leveldb/port/port_posix.h11
-rw-r--r--src/main.cpp633
-rw-r--r--src/main.h195
-rw-r--r--src/makefile.linux-mingw2
-rw-r--r--src/makefile.mingw5
-rw-r--r--src/makefile.osx2
-rw-r--r--src/makefile.unix2
-rw-r--r--src/net.cpp12
-rw-r--r--src/net.h75
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/noui.cpp23
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h6
-rw-r--r--src/qt/addressbookpage.h2
-rw-r--r--src/qt/askpassphrasedialog.cpp14
-rw-r--r--src/qt/askpassphrasedialog.h2
-rw-r--r--src/qt/bitcoin.cpp12
-rw-r--r--src/qt/bitcoinamountfield.h6
-rw-r--r--src/qt/bitcoingui.cpp204
-rw-r--r--src/qt/bitcoingui.h18
-rw-r--r--src/qt/bitcoinstrings.cpp38
-rw-r--r--src/qt/clientmodel.cpp19
-rw-r--r--src/qt/clientmodel.h15
-rw-r--r--src/qt/forms/optionsdialog.ui10
-rw-r--r--src/qt/forms/overviewpage.ui533
-rw-r--r--src/qt/forms/sendcoinsentry.ui26
-rw-r--r--src/qt/locale/bitcoin_en.ts424
-rw-r--r--src/qt/macdockiconhandler.h2
-rw-r--r--src/qt/notificator.h8
-rw-r--r--src/qt/optionsdialog.cpp1
-rw-r--r--src/qt/optionsmodel.cpp27
-rw-r--r--src/qt/optionsmodel.h1
-rw-r--r--src/qt/overviewpage.cpp30
-rw-r--r--src/qt/overviewpage.h8
-rw-r--r--src/qt/qtipcserver.cpp2
-rw-r--r--src/qt/rpcconsole.cpp5
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/transactiontablemodel.h3
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/qt/walletmodel.h4
-rw-r--r--src/rpcblockchain.cpp2
-rw-r--r--src/rpcmining.cpp2
-rw-r--r--src/rpcrawtransaction.cpp145
-rw-r--r--src/rpcwallet.cpp149
-rw-r--r--src/script.cpp31
-rw-r--r--src/script.h13
-rw-r--r--src/serialize.h148
-rw-r--r--src/sync.h40
-rw-r--r--src/test/DoS_tests.cpp16
-rw-r--r--src/test/multisig_tests.cpp22
-rw-r--r--src/test/rpc_tests.cpp99
-rw-r--r--src/test/script_P2SH_tests.cpp6
-rw-r--r--src/test/script_tests.cpp38
-rw-r--r--src/test/test_bitcoin.cpp13
-rw-r--r--src/test/transaction_tests.cpp4
-rw-r--r--src/txdb.cpp19
-rw-r--r--src/txdb.h6
-rw-r--r--src/ui_interface.h68
-rw-r--r--src/util.cpp28
-rw-r--r--src/util.h9
-rw-r--r--src/wallet.cpp83
-rw-r--r--src/wallet.h27
77 files changed, 2325 insertions, 1470 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 725037addc..bfb696da3d 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";
}
@@ -234,6 +229,7 @@ static const CRPCCommand vRPCCommands[] =
{ "sendfrom", &sendfrom, false, false },
{ "sendmany", &sendmany, false, false },
{ "addmultisigaddress", &addmultisigaddress, false, false },
+ { "createmultisig", &createmultisig, true, true },
{ "getrawmempool", &getrawmempool, true, false },
{ "getblock", &getblock, false, false },
{ "getblockhash", &getblockhash, false, false },
@@ -258,6 +254,8 @@ static const CRPCCommand vRPCCommands[] =
{ "sendrawtransaction", &sendrawtransaction, false, false },
{ "gettxoutsetinfo", &gettxoutsetinfo, true, false },
{ "gettxout", &gettxout, true, false },
+ { "lockunspent", &lockunspent, false, false },
+ { "listlockunspent", &listlockunspent, false, false },
};
CRPCTable::CRPCTable()
@@ -361,6 +359,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;
@@ -376,7 +409,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
@@ -401,17 +434,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;
@@ -433,7 +464,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)
@@ -719,7 +750,8 @@ void ThreadRPCServer2(void* parg)
printf("ThreadRPCServer started\n");
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
- if (mapArgs["-rpcpassword"] == "")
+ if ((mapArgs["-rpcpassword"] == "") ||
+ (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"]))
{
unsigned char rand_pwd[32];
RAND_bytes(rand_pwd, 32);
@@ -734,11 +766,12 @@ void ThreadRPCServer2(void* parg)
"rpcuser=bitcoinrpc\n"
"rpcpassword=%s\n"
"(you do not need to remember this password)\n"
+ "The username and password MUST NOT be the same.\n"
"If the file does not exist, create it with owner-readable-only file permissions.\n"),
strWhatAmI.c_str(),
GetConfigFile().string().c_str(),
EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
- _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
}
@@ -829,7 +862,7 @@ void ThreadRPCServer2(void* parg)
}
if (!fListening) {
- uiInterface.ThreadSafeMessageBox(strerr, _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
}
@@ -940,10 +973,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)
@@ -1075,10 +1115,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)
@@ -1160,6 +1205,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
if (strMethod == "addmultisigaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "addmultisigaddress" && n > 1) ConvertTo<Array>(params[1]);
+ if (strMethod == "createmultisig" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "createmultisig" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "listunspent" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listunspent" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "listunspent" && n > 2) ConvertTo<Array>(params[2]);
@@ -1170,6 +1217,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true);
if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]);
+ if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
+ if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
return params;
}
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 9290697664..44050ae1bb 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -158,6 +158,7 @@ extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp);
@@ -176,6 +177,8 @@ extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp);
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 8208854962..279003072e 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -39,6 +39,9 @@ namespace Checkpoints
bool CheckBlock(int nHeight, const uint256& hash)
{
+ if (!GetBoolArg("-checkpoints", true))
+ return true;
+
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
@@ -48,6 +51,9 @@ namespace Checkpoints
int GetTotalBlocksEstimate()
{
+ if (!GetBoolArg("-checkpoints", true))
+ return 0;
+
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
return checkpoints.rbegin()->first;
@@ -55,6 +61,9 @@ namespace Checkpoints
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
{
+ if (!GetBoolArg("-checkpoints", true))
+ return NULL;
+
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
diff --git a/src/clientversion.h b/src/clientversion.h
index e79c306c09..24355d1a54 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -11,6 +11,9 @@
#define CLIENT_VERSION_REVISION 99
#define CLIENT_VERSION_BUILD 0
+// Set to true for release, false for prerelease or test build
+#define CLIENT_VERSION_IS_RELEASE false
+
// Converts the parameter X to a string after macro replacement on X has been performed.
// Don't merge these into one macro!
#define STRINGIZE(X) DO_STRINGIZE(X)
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..94629f3cad 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -38,11 +38,13 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret);
if (!fMockDb)
- DbEnv(0).remove(GetDataDir().string().c_str(), 0);
+ DbEnv(0).remove(strPath.c_str(), 0);
}
CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS)
{
+ fDbEnvInit = false;
+ fMockDb = false;
}
CDBEnv::~CDBEnv()
@@ -55,7 +57,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 +65,17 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
if (fShutdown)
return false;
- pathEnv = pathEnv_;
- filesystem::path pathDataDir = pathEnv;
- filesystem::path pathLogDir = pathDataDir / "database";
+ strPath = path.string();
+ 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 +86,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(strPath.c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -271,14 +272,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 +281,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 +442,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..9c01060a1c 100644
--- a/src/db.h
+++ b/src/db.h
@@ -31,10 +31,9 @@ bool BackupWallet(const CWallet& wallet, const std::string& strDest);
class CDBEnv
{
private:
- bool fDetachDB;
bool fDbEnvInit;
bool fMockDb;
- boost::filesystem::path pathEnv;
+ std::string strPath;
void EnvShutdown();
@@ -47,7 +46,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 +66,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 4d5720306d..7f311fa881 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "txdb.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
@@ -9,6 +10,7 @@
#include "init.h"
#include "util.h"
#include "ui_interface.h"
+
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
@@ -26,6 +28,13 @@ using namespace boost;
CWallet* pwalletMain;
CClientUIInterface uiInterface;
+// Used to pass flags to the Bind() function
+enum BindFlags {
+ BF_NONE = 0,
+ BF_EXPLICIT = (1U << 0),
+ BF_REPORT_ERROR = (1U << 1)
+};
+
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
@@ -78,8 +87,10 @@ void Shutdown(void* parg)
StopNode();
{
LOCK(cs_main);
- pcoinsTip->Flush();
- pblocktree->Flush();
+ if (pblocktree)
+ pblocktree->Flush();
+ if (pcoinsTip)
+ pcoinsTip->Flush();
delete pcoinsTip;
delete pcoinsdbview;
delete pblocktree;
@@ -200,23 +211,22 @@ int main(int argc, char* argv[])
bool static InitError(const std::string &str)
{
- uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR);
return false;
}
bool static InitWarning(const std::string &str)
{
- uiInterface.ThreadSafeMessageBox(str, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
return true;
}
-
-bool static Bind(const CService &addr, bool fError = true) {
- if (IsLimited(addr))
+bool static Bind(const CService &addr, unsigned 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;
}
@@ -234,7 +244,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" +
@@ -249,8 +258,9 @@ std::string HelpMessage()
" -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n" +
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
+ " -checkpoints " + _("Lock in block chain with compiled-in checkpoints (default: 1)") + "\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" +
@@ -263,7 +273,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" +
@@ -293,6 +302,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" +
@@ -308,6 +318,79 @@ 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 (!fRequestShutdown) {
+ CDiskBlockPos pos(nFile, 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 (!fRequestShutdown) {
+ pblocktree->WriteReindexing(false);
+ fReindex = false;
+ printf("Reindexing finished\n");
+ }
+ }
+
+ // hardcoded $DATADIR/bootstrap.dat
+ filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
+ if (filesystem::exists(pathBootstrap) && !fRequestShutdown) {
+ 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 (fRequestShutdown)
+ 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.
@@ -399,6 +482,7 @@ bool AppInit2()
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug");
+ fBenchmark = GetBoolArg("-benchmark");
// -debug implies fDebug*
if (fDebug)
@@ -406,8 +490,6 @@ bool AppInit2()
else
fDebugNet = GetBoolArg("-debugnet");
- bitdb.SetDetach(GetBoolArg("-detachdb", false));
-
#if !defined(WIN32) && !defined(QT_GUI)
fDaemon = GetBoolArg("-daemon");
#else
@@ -459,7 +541,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)
@@ -527,7 +609,7 @@ bool AppInit2()
" Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."), strDataDir.c_str());
- uiInterface.ThreadSafeMessageBox(msg, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ InitWarning(msg);
}
if (r == CDBEnv::RECOVER_FAIL)
return InitError(_("wallet.dat corrupt, salvage failed"));
@@ -602,32 +684,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())
@@ -639,7 +717,9 @@ bool AppInit2()
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
- // ********************************************************* Step 7: load blockchain
+ // ********************************************************* Step 7: load block chain
+
+ fReindex = GetBoolArg("-reindex");
if (!bitdb.Open(GetDataDir()))
{
@@ -649,13 +729,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"));
@@ -714,7 +809,7 @@ bool AppInit2()
{
string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect."));
- uiInterface.ThreadSafeMessageBox(msg, _("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ InitWarning(msg);
}
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin") << "\n";
@@ -772,7 +867,7 @@ bool AppInit2()
if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex();
}
- if (pindexBest != pindexRescan)
+ if (pindexBest && pindexBest != pindexRescan)
{
uiInterface.InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
@@ -788,13 +883,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
@@ -820,7 +915,7 @@ bool AppInit2()
//// debug print
printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size());
- printf("nBestHeight = %d\n", nBestHeight);
+ printf("nBestHeight = %d\n", nBestHeight);
printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size());
printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size());
printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size());
diff --git a/src/irc.cpp b/src/irc.cpp
index 17d5ff1a5a..e8471a6630 100644
--- a/src/irc.cpp
+++ b/src/irc.cpp
@@ -192,6 +192,8 @@ void ThreadIRCSeed(void* parg)
// Make this thread recognisable as the IRC seeding thread
RenameThread("bitcoin-ircseed");
+ printf("ThreadIRCSeed started\n");
+
try
{
ThreadIRCSeed2(parg);
@@ -218,7 +220,8 @@ void ThreadIRCSeed2(void* parg)
if (!GetBoolArg("-irc", false))
return;
- printf("ThreadIRCSeed started\n");
+ printf("ThreadIRCSeed trying to connect...\n");
+
int nErrorWait = 10;
int nRetryWait = 10;
int nNameRetry = 0;
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/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h
index 654a4b9d3d..6ca352e2ca 100644
--- a/src/leveldb/port/port_posix.h
+++ b/src/leveldb/port/port_posix.h
@@ -21,13 +21,20 @@
#else
#define PLATFORM_IS_LITTLE_ENDIAN false
#endif
-#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
+#elif defined(OS_FREEBSD)
+ #include <sys/types.h>
+ #include <sys/endian.h>
+ #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
+#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
#include <sys/types.h>
#include <sys/endian.h>
+#elif defined(OS_HPUX)
+ #define PLATFORM_IS_LITTLE_ENDIAN false
#else
#include <endian.h>
#endif
+
#include <pthread.h>
#ifdef SNAPPY
#include <snappy.h>
@@ -42,7 +49,7 @@
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
- defined(OS_ANDROID)
+ defined(OS_ANDROID) || defined(OS_HPUX)
// Use fread/fwrite/fflush on platforms without _unlocked variants
#define fread_unlocked fread
#define fwrite_unlocked fwrite
diff --git a/src/main.cpp b/src/main.cpp
index 064ac7e10d..61bd6b7b87 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -41,6 +41,9 @@ 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;
+bool fBenchmark = false;
+unsigned int nCoinCacheSize = 5000;
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
@@ -691,13 +694,21 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
if (fCheckInputs)
{
- CCoinsViewCache &view = *pcoinsTip;
+ CCoinsView dummy;
+ CCoinsViewCache view(dummy);
+
+ {
+ LOCK(cs);
+ CCoinsViewMemPool viewMemPool(*pcoinsTip, *this);
+ view.SetBackend(viewMemPool);
// do we already have it?
if (view.HaveCoins(hash))
return false;
// do all inputs exist?
+ // Note that this does not check for the presence of actual outputs (see the next check for that),
+ // only helps filling in pfMissingInputs (to determine missing vs spent).
BOOST_FOREACH(const CTxIn txin, tx.vin) {
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
@@ -706,9 +717,17 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
}
}
+ // are the actual inputs available?
if (!tx.HaveInputs(view))
return error("CTxMemPool::accept() : inputs already spent");
+ // Bring the best block into scope
+ view.GetBestBlock();
+
+ // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool
+ view.SetBackend(dummy);
+ }
+
// Check for non-standard pay-to-script-hash in inputs
if (!tx.AreInputsStandard(view) && !fTestNet)
return error("CTxMemPool::accept() : nonstandard transaction input");
@@ -738,7 +757,6 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
int64 nNow = GetTime();
{
- LOCK(cs);
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
@@ -754,7 +772,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!tx.CheckInputs(view, CS_ALWAYS, true, false))
+ if (!tx.CheckInputs(view, CS_ALWAYS, SCRIPT_VERIFY_P2SH))
{
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
@@ -801,7 +819,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
}
-bool CTxMemPool::remove(CTransaction &tx)
+bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive)
{
// Remove transaction from memory pool
{
@@ -809,6 +827,13 @@ bool CTxMemPool::remove(CTransaction &tx)
uint256 hash = tx.GetHash();
if (mapTx.count(hash))
{
+ if (fRecursive) {
+ for (unsigned int i = 0; i < tx.vout.size(); i++) {
+ std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i));
+ if (it != mapNextTx.end())
+ remove(*it->second.ptx, true);
+ }
+ }
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
mapTx.erase(hash);
@@ -818,6 +843,21 @@ bool CTxMemPool::remove(CTransaction &tx)
return true;
}
+bool CTxMemPool::removeConflicts(const CTransaction &tx)
+{
+ // Remove transactions which depend on inputs of tx, recursively
+ LOCK(cs);
+ BOOST_FOREACH(const CTxIn &txin, tx.vin) {
+ std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout);
+ if (it != mapNextTx.end()) {
+ const CTransaction &txConflict = *it->second.ptx;
+ if (txConflict != tx)
+ remove(txConflict, true);
+ }
+ }
+ return true;
+}
+
void CTxMemPool::clear()
{
LOCK(cs);
@@ -981,21 +1021,16 @@ CBlockIndex* FindBlockByHeight(int nHeight)
return pblockindex;
}
-bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
+bool CBlock::ReadFromDisk(const CBlockIndex* pindex)
{
- if (!fReadTransactions)
- {
- *this = pindex->GetBlockHeader();
- return true;
- }
- if (!ReadFromDisk(pindex->GetBlockPos(), fReadTransactions))
+ if (!ReadFromDisk(pindex->GetBlockPos()))
return false;
if (GetHash() != pindex->GetBlockHash())
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
return true;
}
-uint256 static GetOrphanRoot(const CBlock* pblock)
+uint256 static GetOrphanRoot(const CBlockHeader* pblock)
{
// Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock))
@@ -1042,7 +1077,7 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
return bnResult.GetCompact();
}
-unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock)
+unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();
@@ -1129,7 +1164,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;
@@ -1151,11 +1186,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
uiInterface.NotifyBlocksChanged();
}
printf("InvalidChainFound: invalid block=%s height=%d work=%s date=%s\n",
- pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight,
+ BlockHashStr(pindexNew->GetBlockHash()).c_str(), pindexNew->nHeight,
pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S",
pindexNew->GetBlockTime()).c_str());
printf("InvalidChainFound: current best=%s height=%d work=%s date=%s\n",
- hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(),
+ BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(),
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
@@ -1181,7 +1216,7 @@ bool ConnectBestBlock() {
pindexNewBest = *it;
}
- if (pindexNewBest == pindexBest)
+ if (pindexNewBest == pindexBest || (pindexBest && pindexNewBest->bnChainWork == pindexBest->bnChainWork))
return true; // nothing to do
// check ancestry
@@ -1206,9 +1241,12 @@ bool ConnectBestBlock() {
if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) {
reverse(vAttach.begin(), vAttach.end());
- BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach)
+ BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
+ if (fRequestShutdown)
+ break;
if (!SetBestChain(pindexSwitch))
return false;
+ }
return true;
}
pindexTest = pindexTest->pprev;
@@ -1216,7 +1254,7 @@ bool ConnectBestBlock() {
} while(true);
}
-void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
+void CBlockHeader::UpdateTime(const CBlockIndex* pindexPrev)
{
nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
@@ -1291,7 +1329,7 @@ bool CTransaction::UpdateCoins(CCoinsViewCache &inputs, CTxUndo &txundo, int nHe
bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const
{
- if (!IsCoinBase()) {
+ if (!IsCoinBase()) {
// first check whether information about the prevout hash is available
for (unsigned int i = 0; i < vin.size(); i++) {
const COutPoint &prevout = vin[i].prevout;
@@ -1310,7 +1348,7 @@ bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const
return true;
}
-bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmode, bool fStrictPayToScriptHash, bool fStrictEncodings) const
+bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmode, unsigned int flags) const
{
if (!IsCoinBase())
{
@@ -1319,7 +1357,9 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod
if (!HaveInputs(inputs))
return error("CheckInputs() : %s inputs unavailable", GetHash().ToString().substr(0,10).c_str());
- CBlockIndex *pindexBlock = inputs.GetBestBlock();
+ // While checking, GetBestBlock() refers to the parent block.
+ // This is also true for mempool checks.
+ int nSpendHeight = inputs.GetBestBlock()->nHeight + 1;
int64 nValueIn = 0;
int64 nFees = 0;
for (unsigned int i = 0; i < vin.size(); i++)
@@ -1329,8 +1369,8 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod
// If prev is coinbase, check that it's matured
if (coins.IsCoinBase()) {
- if (pindexBlock->nHeight - coins.nHeight < COINBASE_MATURITY)
- return error("CheckInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - coins.nHeight);
+ if (nSpendHeight - coins.nHeight < COINBASE_MATURITY)
+ return error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight);
}
// Check for negative or overflow input values
@@ -1356,23 +1396,17 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod
// Helps prevent CPU exhaustion attacks.
// Skip ECDSA signature verification when connecting blocks
- // before the last blockchain checkpoint. This is safe because block merkle hashes are
+ // before the last block chain checkpoint. This is safe because block merkle hashes are
// still computed and checked, and any change will be caught at the next checkpoint.
- if (csmode == CS_ALWAYS ||
+ if (csmode == CS_ALWAYS ||
(csmode == CS_AFTER_CHECKPOINT && inputs.GetBestBlock()->nHeight >= Checkpoints::GetTotalBlocksEstimate())) {
for (unsigned int i = 0; i < vin.size(); i++) {
const COutPoint &prevout = vin[i].prevout;
const CCoins &coins = inputs.GetCoins(prevout.hash);
// Verify signature
- if (!VerifySignature(coins, *this, i, fStrictPayToScriptHash, fStrictEncodings, 0)) {
- // only during transition phase for P2SH: do not invoke anti-DoS code for
- // potentially old clients relaying bad P2SH transactions
- if (fStrictPayToScriptHash && VerifySignature(coins, *this, i, false, fStrictEncodings, 0))
- return error("CheckInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
-
+ if (!VerifySignature(coins, *this, i, flags, 0))
return DoS(100,error("CheckInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
- }
}
}
}
@@ -1402,7 +1436,7 @@ bool CTransaction::ClientCheckInputs() const
return false;
// Verify signature
- if (!VerifySignature(CCoins(txPrev, -1), *this, i, true, false, 0))
+ if (!VerifySignature(CCoins(txPrev, -1), *this, i, SCRIPT_VERIFY_P2SH, 0))
return error("ConnectInputs() : VerifySignature failed");
///// this is redundant with the mempool.mapNextTx stuff,
@@ -1505,17 +1539,19 @@ void static FlushBlockFile()
{
LOCK(cs_LastBlockFile);
- CDiskBlockPos posOld;
- posOld.nFile = nLastBlockFile;
- posOld.nPos = 0;
+ CDiskBlockPos posOld(nLastBlockFile, 0);
FILE *fileOld = OpenBlockFile(posOld);
- FileCommit(fileOld);
- fclose(fileOld);
+ if (fileOld) {
+ FileCommit(fileOld);
+ fclose(fileOld);
+ }
fileOld = OpenUndoFile(posOld);
- FileCommit(fileOld);
- fclose(fileOld);
+ if (fileOld) {
+ FileCommit(fileOld);
+ fclose(fileOld);
+ }
}
bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
@@ -1541,7 +1577,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
// Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the
// two in the chain that violate it. This prevents exploiting the issue against nodes in their
// initial block download.
- bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
+ bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash.
+ !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
for (unsigned int i=0; i<vtx.size(); i++) {
@@ -1557,12 +1594,16 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
CBlockUndo blockundo;
+ int64 nStart = GetTimeMicros();
int64 nFees = 0;
+ int nInputs = 0;
unsigned int nSigOps = 0;
for (unsigned int i=0; i<vtx.size(); i++)
{
+
const CTransaction &tx = vtx[i];
+ nInputs += tx.vin.size();
nSigOps += tx.GetLegacySigOpCount();
if (nSigOps > MAX_BLOCK_SIGOPS)
return DoS(100, error("ConnectBlock() : too many sigops"));
@@ -1584,7 +1625,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
nFees += tx.GetValueIn(view)-tx.GetValueOut();
- if (!tx.CheckInputs(view, CS_AFTER_CHECKPOINT, fStrictPayToScriptHash, false))
+ if (!tx.CheckInputs(view, CS_AFTER_CHECKPOINT, fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE))
return false;
}
@@ -1593,7 +1634,14 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return error("ConnectBlock() : UpdateInputs failed");
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
+
}
+ int64 nTime = GetTimeMicros() - nStart;
+ if (fBenchmark)
+ printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
+
+ if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
+ return error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees));
if (fJustCheck)
return true;
@@ -1620,7 +1668,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return error("ConnectBlock() : WriteBlockIndex failed");
}
- // add this block to the view's blockchain
+ // add this block to the view's block chain
if (!view.SetBestBlock(pindex))
return false;
@@ -1633,7 +1681,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
bool SetBestChain(CBlockIndex* pindexNew)
{
- CCoinsViewCache &view = *pcoinsTip;
+ // All modifications to the coin state will be done in this cache.
+ // Only when all have succeeded, we push it to pcoinsTip.
+ CCoinsViewCache view(*pcoinsTip, true);
// special case for attaching the genesis block
// note that no ConnectBlock is called, so its coinbase output is non-spendable
@@ -1653,7 +1703,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Find the fork (typically, there is none)
CBlockIndex* pfork = view.GetBestBlock();
CBlockIndex* plonger = pindexNew;
- while (pfork != plonger)
+ while (pfork && pfork != plonger)
{
while (plonger->nHeight > pfork->nHeight)
if (!(plonger = plonger->pprev))
@@ -1676,8 +1726,8 @@ bool SetBestChain(CBlockIndex* pindexNew)
reverse(vConnect.begin(), vConnect.end());
if (vDisconnect.size() > 0) {
- printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
- printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
+ printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), BlockHashStr(pfork->GetBlockHash()).c_str(), BlockHashStr(pindexBest->GetBlockHash()).c_str());
+ printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), BlockHashStr(pfork->GetBlockHash()).c_str(), BlockHashStr(pindexNew->GetBlockHash()).c_str());
}
// Disconnect shorter branch
@@ -1686,15 +1736,17 @@ bool SetBestChain(CBlockIndex* pindexNew)
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("SetBestBlock() : ReadFromDisk for disconnect failed");
- CCoinsViewCache viewTemp(view, true);
- if (!block.DisconnectBlock(pindex, viewTemp))
- return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
- if (!viewTemp.Flush())
- return error("SetBestBlock() : Cache flush failed after disconnect");
-
- // Queue memory transactions to resurrect
+ int64 nStart = GetTimeMicros();
+ if (!block.DisconnectBlock(pindex, view))
+ return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
+ if (fBenchmark)
+ printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
+
+ // Queue memory transactions to resurrect.
+ // We only do this for blocks after the last checkpoint (reorganisation before that
+ // point should only happen with -reindex/-loadblock, or a misbehaving peer.
BOOST_FOREACH(const CTransaction& tx, block.vtx)
- if (!tx.IsCoinBase())
+ if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate())
vResurrect.push_back(tx);
}
@@ -1704,26 +1756,35 @@ bool SetBestChain(CBlockIndex* pindexNew)
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("SetBestBlock() : ReadFromDisk for connect failed");
- CCoinsViewCache viewTemp(view, true);
- if (!block.ConnectBlock(pindex, viewTemp)) {
+ int64 nStart = GetTimeMicros();
+ if (!block.ConnectBlock(pindex, view)) {
InvalidChainFound(pindexNew);
InvalidBlockFound(pindex);
- return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
}
- if (!viewTemp.Flush())
- return error("SetBestBlock() : Cache flush failed after connect");
+ if (fBenchmark)
+ printf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
// Queue memory transactions to delete
BOOST_FOREACH(const CTransaction& tx, block.vtx)
vDelete.push_back(tx);
}
+ // Flush changes to global coin state
+ int64 nStart = GetTimeMicros();
+ int nModified = view.GetCacheSize();
+ if (!view.Flush())
+ return error("SetBestBlock() : unable to modify coin state");
+ int64 nTime = GetTimeMicros() - nStart;
+ if (fBenchmark)
+ printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified);
+
// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload();
- if (!fIsInitialDownload || view.GetCacheSize()>5000) {
+ if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) {
FlushBlockFile();
pblocktree->Sync();
- if (!view.Flush())
+ if (!pcoinsTip->Flush())
return false;
}
@@ -1742,11 +1803,13 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect)
- tx.AcceptToMemoryPool(false);
+ tx.AcceptToMemoryPool();
// Delete redundant memory transactions that are in the connected branch
- BOOST_FOREACH(CTransaction& tx, vDelete)
+ BOOST_FOREACH(CTransaction& tx, vDelete) {
mempool.remove(tx);
+ mempool.removeConflicts(tx);
+ }
// Update best block in wallet (so we can detect restored wallets)
if (!fIsInitialDownload)
@@ -1764,7 +1827,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
printf("SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s\n",
- hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx,
+ BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx,
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
// Check the version of the last 100 blocks to see if we need to upgrade:
@@ -1802,7 +1865,7 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
- return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str());
+ return error("AddToBlockIndex() : %s already exists", BlockHashStr(hash).c_str());
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(*this);
@@ -1846,35 +1909,50 @@ 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);
+ fUpdatedLast = true;
+ }
+ } 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) {
+ if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) {
+ 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);
+ }
+ }
+ else
+ return error("FindBlockPos() : out of disk space");
}
- fclose(file);
}
if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile))
@@ -1910,12 +1988,16 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;
unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;
if (nNewChunks > nOldChunks) {
- FILE *file = OpenUndoFile(pos);
- if (file) {
- printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);
- AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos);
+ if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) {
+ FILE *file = OpenUndoFile(pos);
+ if (file) {
+ printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile);
+ AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos);
+ fclose(file);
+ }
}
- fclose(file);
+ else
+ return error("FindUndoPos() : out of disk space");
}
return true;
@@ -1951,9 +2033,13 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
+ // Build the merkle tree already. We need it anyway later, and it makes the
+ // block cache the transaction hashes, which means they don't need to be
+ // recalculated many times during this block's validation.
+ BuildMerkleTree();
+
// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
- BuildMerkleTree();
set<uint256> uniqueTx;
for (unsigned int i=0; i<vtx.size(); i++) {
uniqueTx.insert(GetTxHash(i));
@@ -1976,7 +2062,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();
@@ -1984,60 +2070,65 @@ 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)
+ 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");
@@ -2066,14 +2157,14 @@ 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();
if (mapBlockIndex.count(hash))
- return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str());
+ return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, BlockHashStr(hash).c_str());
if (mapOrphanBlocks.count(hash))
- return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());
+ return error("ProcessBlock() : already have block (orphan) %s", BlockHashStr(hash).c_str());
// Preliminary checks
if (!pblock->CheckBlock())
@@ -2104,9 +2195,9 @@ 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());
+ printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", BlockHashStr(pblock->hashPrevBlock).c_str());
// Accept orphans as long as there is a node to request its parents from
if (pfrom) {
@@ -2121,7 +2212,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
@@ -2162,10 +2253,10 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes)
{
fShutdown = true;
- string strMessage = _("Warning: Disk space is low!");
+ string strMessage = _("Error: Disk space is low!");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- uiInterface.ThreadSafeMessageBox(strMessage, "Bitcoin", CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
+ uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR);
StartShutdown();
return false;
}
@@ -2258,14 +2349,19 @@ bool static LoadBlockIndexDB()
printf("LoadBlockIndex(): last block file = %i\n", nLastBlockFile);
if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile))
printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
-
+
+ // 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;
+
// Load hashBestChain pointer to end of best chain
pindexBest = pcoinsTip->GetBestBlock();
if (pindexBest == NULL)
- {
- if (pindexGenesisBlock == NULL)
- return true;
- }
+ return true;
hashBestChain = pindexBest->GetBlockHash();
nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork;
@@ -2278,12 +2374,9 @@ bool static LoadBlockIndexDB()
pindex = pindexPrev;
}
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
- hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
+ BlockHashStr(hashBestChain).c_str(), nBestHeight,
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
- // Load bnBestInvalidWork, OK if it doesn't exist
- pblocktree->ReadBestInvalidWork(bnBestInvalidWork);
-
// Verify blocks in the best chain
int nCheckLevel = GetArg("-checklevel", 1);
int nCheckDepth = GetArg( "-checkblocks", 2500);
@@ -2317,7 +2410,7 @@ bool static LoadBlockIndexDB()
return true;
}
-bool LoadBlockIndex(bool fAllowNew)
+bool LoadBlockIndex()
{
if (fTestNet)
{
@@ -2328,6 +2421,9 @@ bool LoadBlockIndex(bool fAllowNew)
hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
}
+ if (fReindex)
+ return true;
+
//
// Load block index from databases
//
@@ -2339,9 +2435,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)
@@ -2467,113 +2560,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() && !fRequestShutdown) {
+ 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=
- uiInterface.InitMessage(_("Starting block import..."));
- 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)) {
- uiInterface.InitMessage(_("Importing bootstrap blockchain data file."));
-
- 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]--;
-}
-
@@ -2596,9 +2647,13 @@ string GetWarnings(string strFor)
int nPriority = 0;
string strStatusBar;
string strRPC;
+
if (GetBoolArg("-testsafemode"))
strRPC = "test";
+ if (!CLIENT_VERSION_IS_RELEASE)
+ strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications");
+
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
@@ -2681,7 +2736,6 @@ unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
- static map<CService, CPubKey> mapReuseKey;
RandAddSeedPerfmon();
if (fDebug)
printf("received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size());
@@ -2780,7 +2834,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) &&
@@ -2917,7 +2971,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]));
@@ -3022,12 +3076,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (pindex)
pindex = pindex->pnext;
int nLimit = 500;
- printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+ printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), BlockHashStr(hashStop).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
- printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ printf(" getblocks stopping at %d %s\n", pindex->nHeight, BlockHashStr(pindex->GetBlockHash()).c_str());
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
@@ -3035,7 +3089,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
- printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, BlockHashStr(pindex->GetBlockHash()).c_str());
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
@@ -3066,9 +3120,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pindex = pindex->pnext;
}
+ // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = 2000;
- printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str());
+ printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), BlockHashStr(hashStop).c_str());
for (; pindex; pindex = pindex->pnext)
{
vHeaders.push_back(pindex->GetBlockHeader());
@@ -3147,12 +3202,12 @@ 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;
- printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str());
+ printf("received block %s\n", BlockHashStr(block.GetHash()).c_str());
// block.print();
CInv inv(MSG_BLOCK, block.GetHash());
@@ -3189,53 +3244,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
- else if (strCommand == "checkorder")
- {
- uint256 hashReply;
- vRecv >> hashReply;
-
- if (!GetBoolArg("-allowreceivebyip"))
- {
- pfrom->PushMessage("reply", hashReply, (int)2, string(""));
- return true;
- }
-
- CWalletTx order;
- vRecv >> order;
-
- /// we have a chance to check the order here
-
- // Keep giving the same key to the same ip until they use it
- if (!mapReuseKey.count(pfrom->addr))
- pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
-
- // Send back approval of order and pubkey to use
- CScript scriptPubKey;
- scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
- pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
- }
-
-
- else if (strCommand == "reply")
- {
- uint256 hashReply;
- vRecv >> hashReply;
-
- CRequestTracker tracker;
- {
- LOCK(pfrom->cs_mapRequests);
- map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
- if (mi != pfrom->mapRequests.end())
- {
- tracker = (*mi).second;
- pfrom->mapRequests.erase(mi);
- }
- }
- if (!tracker.IsNull())
- tracker.fn(tracker.param1, vRecv);
- }
-
-
else if (strCommand == "ping")
{
if (pfrom->nVersion > BIP0031_VERSION)
@@ -3724,13 +3732,8 @@ public:
}
};
-const char* pszDummy = "\0\0";
-CScript scriptDummy(std::vector<unsigned char>(pszDummy, pszDummy + sizeof(pszDummy)));
-
CBlock* CreateNewBlock(CReserveKey& reservekey)
{
- CBlockIndex* pindexPrev = pindexBest;
-
// Create new block
auto_ptr<CBlock> pblock(new CBlock());
if (!pblock.get())
@@ -3774,11 +3777,13 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
int64 nFees = 0;
{
LOCK2(cs_main, mempool.cs);
+ CBlockIndex* pindexPrev = pindexBest;
CCoinsViewCache view(*pcoinsTip, true);
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
+ bool fPrintPriority = GetBoolArg("-printpriority");
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
@@ -3828,7 +3833,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
int64 nValueIn = coins.vout[txin.prevout.n].nValue;
nTotalIn += nValueIn;
- int nConf = pindexPrev->nHeight - coins.nHeight;
+ int nConf = pindexPrev->nHeight - coins.nHeight + 1;
dPriority += (double)nValueIn * nConf;
}
@@ -3907,7 +3912,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
- if (!tx.CheckInputs(viewTemp, CS_ALWAYS, true, false))
+ if (!tx.CheckInputs(viewTemp, CS_ALWAYS, SCRIPT_VERIFY_P2SH))
continue;
CTxUndo txundo;
@@ -3925,7 +3930,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
nBlockSigOps += nTxSigOps;
nFees += nTxFees;
- if (fDebug && GetBoolArg("-printpriority"))
+ if (fPrintPriority)
{
printf("priority %.1f feeperkb %.1f txid %s\n",
dPriority, dFeePerKb, tx.GetHash().ToString().c_str());
@@ -3960,7 +3965,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
pblock->UpdateTime(pindexPrev);
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get());
pblock->nNonce = 0;
- pblock->vtx[0].vin[0].scriptSig = scriptDummy;
+ pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
CBlockIndex indexDummy(*pblock);
indexDummy.pprev = pindexPrev;
diff --git a/src/main.h b/src/main.h
index 75ee7a9be5..fdaec3469e 100644
--- a/src/main.h
+++ b/src/main.h
@@ -20,26 +20,38 @@ class CReserveKey;
class CAddress;
class CInv;
-class CRequestTracker;
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;
+/** The maximum size for mined blocks */
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
+/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
+/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
+/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
+/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
+/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
+/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
+/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
static const int64 MIN_TX_FEE = 50000;
+/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */
static const int64 MIN_RELAY_TX_FEE = 10000;
+/** No amount larger than this (in satoshi) is valid */
static const int64 MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
+/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
-// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
+/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
#ifdef USE_UPNP
static const int fHaveUPnP = true;
@@ -76,6 +88,9 @@ extern CCriticalSection cs_setpwalletRegistered;
extern std::set<CWallet*> setpwalletRegistered;
extern unsigned char pchMessageStart[4];
extern bool fImporting;
+extern bool fReindex;
+extern bool fBenchmark;
+extern unsigned int nCoinCacheSize;
// Settings
extern int64 nTransactionFee;
@@ -93,32 +108,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);
@@ -131,6 +175,11 @@ CBlockIndex * InsertBlockIndex(uint256 hash);
+static inline std::string BlockHashStr(const uint256& hash)
+{
+ return hash.ToString();
+}
+
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
class CDiskBlockPos
@@ -144,6 +193,15 @@ public:
READWRITE(VARINT(nPos));
)
+ CDiskBlockPos() {
+ SetNull();
+ }
+
+ CDiskBlockPos(int nFileIn, unsigned int nPosIn) {
+ nFile = nFileIn;
+ nPos = nPosIn;
+ }
+
friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) {
return (a.nFile == b.nFile && a.nPos == b.nPos);
}
@@ -582,7 +640,7 @@ public:
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set
- bool CheckInputs(CCoinsViewCache &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true) const;
+ bool CheckInputs(CCoinsViewCache &view, enum CheckSig_mode csmode, unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC) const;
// Apply the effects of this transaction on the UTXO set represented by view
bool UpdateCoins(CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
@@ -690,7 +748,6 @@ public:
bool WriteToDisk(CDiskBlockPos &pos)
{
-
// Open history file to append
CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
if (!fileout)
@@ -703,7 +760,7 @@ public:
// Write undo data
long fileOutPos = ftell(fileout);
if (fileOutPos < 0)
- return error("CBlock::WriteToDisk() : ftell failed");
+ return error("CBlockUndo::WriteToDisk() : ftell failed");
pos.nPos = (unsigned int)fileOutPos;
fileout << *this;
@@ -714,7 +771,6 @@ public:
return true;
}
-
};
/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
@@ -777,7 +833,7 @@ public:
// unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
std::vector<CTxOut> vout;
- // at which height this transaction was included in the active blockchain
+ // at which height this transaction was included in the active block chain
int nHeight;
// version of the CTransaction; accesses to this value should probably check for nHeight as well,
@@ -798,7 +854,7 @@ public:
// equality test
friend bool operator==(const CCoins &a, const CCoins &b) {
- return a.fCoinBase == b.fCoinBase &&
+ return a.fCoinBase == b.fCoinBase &&
a.nHeight == b.nHeight &&
a.nVersion == b.nVersion &&
a.vout == b.vout;
@@ -1025,7 +1081,7 @@ public:
* in the block is a special one that creates a new coin owned by the creator
* of the block.
*/
-class CBlock
+class CBlockHeader
{
public:
// header
@@ -1037,17 +1093,7 @@ public:
unsigned int nBits;
unsigned int nNonce;
- // network and disk
- std::vector<CTransaction> vtx;
-
- // memory only
- mutable std::vector<uint256> vMerkleTree;
-
- // Denial-of-service detection:
- mutable int nDoS;
- bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
-
- CBlock()
+ CBlockHeader()
{
SetNull();
}
@@ -1061,25 +1107,16 @@ public:
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
-
- // ConnectBlock depends on vtx being last so it can calculate offset
- if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
- READWRITE(vtx);
- else if (fRead)
- const_cast<CBlock*>(this)->vtx.clear();
)
void SetNull()
{
- nVersion = CBlock::CURRENT_VERSION;
+ nVersion = CBlockHeader::CURRENT_VERSION;
hashPrevBlock = 0;
hashMerkleRoot = 0;
nTime = 0;
nBits = 0;
nNonce = 0;
- vtx.clear();
- vMerkleTree.clear();
- nDoS = 0;
}
bool IsNull() const
@@ -1098,7 +1135,45 @@ public:
}
void UpdateTime(const CBlockIndex* pindexPrev);
+};
+
+class CBlock : public CBlockHeader
+{
+public:
+ // network and disk
+ std::vector<CTransaction> vtx;
+
+ // memory only
+ mutable std::vector<uint256> vMerkleTree;
+ // Denial-of-service detection:
+ mutable int nDoS;
+ bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
+
+ CBlock()
+ {
+ SetNull();
+ }
+
+ CBlock(const CBlockHeader &header)
+ {
+ SetNull();
+ *((CBlockHeader*)this) = header;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(*(CBlockHeader*)this);
+ READWRITE(vtx);
+ )
+
+ void SetNull()
+ {
+ CBlockHeader::SetNull();
+ vtx.clear();
+ vMerkleTree.clear();
+ nDoS = 0;
+ }
uint256 BuildMerkleTree() const
{
@@ -1183,7 +1258,7 @@ public:
return true;
}
- bool ReadFromDisk(const CDiskBlockPos &pos, bool fReadTransactions = true)
+ bool ReadFromDisk(const CDiskBlockPos &pos)
{
SetNull();
@@ -1191,8 +1266,6 @@ public:
CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (!filein)
return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
- if (!fReadTransactions)
- filein.nType |= SER_BLOCKHEADERONLY;
// Read block
try {
@@ -1214,9 +1287,9 @@ public:
void print() const
{
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n",
- GetHash().ToString().substr(0,20).c_str(),
+ BlockHashStr(GetHash()).c_str(),
nVersion,
- hashPrevBlock.ToString().substr(0,20).c_str(),
+ BlockHashStr(hashPrevBlock).c_str(),
hashMerkleRoot.ToString().substr(0,10).c_str(),
nTime, nBits, nNonce,
vtx.size());
@@ -1239,7 +1312,7 @@ public:
bool ConnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false);
// Read a block from disk
- bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
+ bool ReadFromDisk(const CBlockIndex* pindex);
// Add this block to the block index, and if necessary, switch the active block chain to this
bool AddToBlockIndex(const CDiskBlockPos &pos);
@@ -1248,7 +1321,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);
};
@@ -1403,7 +1477,7 @@ public:
nNonce = 0;
}
- CBlockIndex(CBlock& block)
+ CBlockIndex(CBlockHeader& block)
{
phashBlock = NULL;
pprev = NULL;
@@ -1429,8 +1503,7 @@ public:
if (nStatus & BLOCK_HAVE_DATA) {
ret.nFile = nFile;
ret.nPos = nDataPos;
- } else
- ret.SetNull();
+ }
return ret;
}
@@ -1439,14 +1512,13 @@ public:
if (nStatus & BLOCK_HAVE_UNDO) {
ret.nFile = nFile;
ret.nPos = nUndoPos;
- } else
- ret.SetNull();
+ }
return ret;
}
- CBlock GetBlockHeader() const
+ CBlockHeader GetBlockHeader() const
{
- CBlock block;
+ CBlockHeader block;
block.nVersion = nVersion;
if (pprev)
block.hashPrevBlock = pprev->GetBlockHash();
@@ -1526,7 +1598,7 @@ public:
return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, pnext, nHeight,
hashMerkleRoot.ToString().substr(0,10).c_str(),
- GetBlockHash().ToString().substr(0,20).c_str());
+ BlockHashStr(GetBlockHash()).c_str());
}
void print() const
@@ -1590,7 +1662,7 @@ public:
uint256 GetBlockHash() const
{
- CBlock block;
+ CBlockHeader block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
@@ -1607,7 +1679,7 @@ public:
str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s)",
GetBlockHash().ToString().c_str(),
- hashPrev.ToString().substr(0,20).c_str());
+ BlockHashStr(hashPrev).c_str());
return str;
}
@@ -1767,7 +1839,8 @@ public:
bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs);
bool addUnchecked(const uint256& hash, CTransaction &tx);
- bool remove(CTransaction &tx);
+ bool remove(const CTransaction &tx, bool fRecursive = false);
+ bool removeConflicts(const CTransaction &tx);
void clear();
void queryHashes(std::vector<uint256>& vtxid);
void pruneSpent(const uint256& hash, CCoins &coins);
@@ -1820,8 +1893,15 @@ public:
// Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex);
+
+ // Do a bulk modification (multiple SetCoins + one SetBestBlock)
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+
+ // Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats);
+
+ // As we use CCoinsViews polymorphically, have a virtual destructor
+ virtual ~CCoinsView() {}
};
/** CCoinsView backed by another CCoinsView */
@@ -1851,14 +1931,25 @@ protected:
public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
+
+ // Standard CCoinsView methods
bool GetCoins(uint256 txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins);
bool HaveCoins(uint256 txid);
- CCoins &GetCoins(uint256 txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+
+ // Return a modifiable reference to a CCoins. Check HaveCoins first.
+ // Many methods explicitly require a CCoinsViewCache because of this method, to reduce
+ // copying.
+ CCoins &GetCoins(uint256 txid);
+
+ // Push the modifications applied to this cache to its base.
+ // Failure to call this method before destruction will cause the changes to be forgotten.
bool Flush();
+
+ // Calculate the size of the cache (in number of transactions)
unsigned int GetCacheSize();
private:
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index f4adbb2bff..47dc7c5c40 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -92,7 +92,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += -I"$(CURDIR)/leveldb/include"
DEFS += -I"$(CURDIR)/leveldb/helpers"
leveldb/libleveldb.a:
- @echo "Building LevelDB ..."; cd leveldb; TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" make libleveldb.a libmemenv.a; cd ..
+ @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.a
obj/build.h: FORCE
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 945ec77099..22d65d6703 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -94,9 +94,10 @@ test check: test_bitcoin.exe FORCE
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
+# TODO: If this fails, try adding a ranlib libleveldb.a && ranlib libmemenv.a
leveldb/libleveldb.a:
- cd leveldb; make libleveldb.a libmemenv.a; cd ..
-obj/leveldb.o: leveldb/libleveldb.lib
+ cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
+obj/leveldb.o: leveldb/libleveldb.a
obj/%.o: %.cpp $(HEADERS)
g++ -c $(CFLAGS) -o $@ $<
diff --git a/src/makefile.osx b/src/makefile.osx
index f3e17d0d13..25164c8679 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -128,7 +128,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..
+ @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.a
# auto-generated dependencies:
diff --git a/src/makefile.unix b/src/makefile.unix
index df05f7990a..9e17e8ace2 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -144,7 +144,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..;
+ @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
obj/leveldb.o: leveldb/libleveldb.a
# auto-generated dependencies:
diff --git a/src/net.cpp b/src/net.cpp
index 2598f0214e..b54f8c15f7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -710,13 +710,9 @@ void ThreadSocketHandler2(void* parg)
TRY_LOCK(pnode->cs_vRecv, lockRecv);
if (lockRecv)
{
- TRY_LOCK(pnode->cs_mapRequests, lockReq);
- if (lockReq)
- {
- TRY_LOCK(pnode->cs_inventory, lockInv);
- if (lockInv)
- fDelete = true;
- }
+ TRY_LOCK(pnode->cs_inventory, lockInv);
+ if (lockInv)
+ fDelete = true;
}
}
}
@@ -1313,6 +1309,8 @@ void DumpAddresses()
void ThreadDumpAddress2(void* parg)
{
+ printf("ThreadDumpAddress started\n");
+
vnThreadsRunning[THREAD_DUMPADDRESS]++;
while (!fShutdown)
{
diff --git a/src/net.h b/src/net.h
index 5e1564f9ca..c43e438d5a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -19,7 +19,6 @@
#include "protocol.h"
#include "addrman.h"
-class CRequestTracker;
class CNode;
class CBlockIndex;
extern int nBestHeight;
@@ -68,31 +67,6 @@ void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
-enum
-{
- MSG_TX = 1,
- MSG_BLOCK,
-};
-
-class CRequestTracker
-{
-public:
- void (*fn)(void*, CDataStream&);
- void* param1;
-
- explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
- {
- fn = fnIn;
- param1 = param1In;
- }
-
- bool IsNull()
- {
- return fn == NULL;
- }
-};
-
-
/** Thread types */
enum threadId
{
@@ -189,8 +163,6 @@ protected:
public:
int64 nReleaseTime;
- std::map<uint256, CRequestTracker> mapRequests;
- CCriticalSection cs_mapRequests;
uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
@@ -564,53 +536,6 @@ public:
}
}
-
- void PushRequest(const char* pszCommand,
- void (*fn)(void*, CDataStream&), void* param1)
- {
- uint256 hashReply;
- RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
-
- {
- LOCK(cs_mapRequests);
- mapRequests[hashReply] = CRequestTracker(fn, param1);
- }
-
- PushMessage(pszCommand, hashReply);
- }
-
- template<typename T1>
- void PushRequest(const char* pszCommand, const T1& a1,
- void (*fn)(void*, CDataStream&), void* param1)
- {
- uint256 hashReply;
- RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
-
- {
- LOCK(cs_mapRequests);
- mapRequests[hashReply] = CRequestTracker(fn, param1);
- }
-
- PushMessage(pszCommand, hashReply, a1);
- }
-
- template<typename T1, typename T2>
- void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
- void (*fn)(void*, CDataStream&), void* param1)
- {
- uint256 hashReply;
- RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
-
- {
- LOCK(cs_mapRequests);
- mapRequests[hashReply] = CRequestTracker(fn, param1);
- }
-
- PushMessage(pszCommand, hashReply, a1, a2);
- }
-
-
-
void PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd);
bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0);
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/noui.cpp b/src/noui.cpp
index db25f2d285..204e76aba7 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -2,20 +2,37 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "ui_interface.h"
#include "init.h"
#include "bitcoinrpc.h"
#include <string>
-static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
+static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
+ std::string strCaption;
+ // Check for usage of predefined caption
+ switch (style) {
+ case CClientUIInterface::MSG_ERROR:
+ strCaption += _("Error");
+ break;
+ case CClientUIInterface::MSG_WARNING:
+ strCaption += _("Warning");
+ break;
+ case CClientUIInterface::MSG_INFORMATION:
+ strCaption += _("Information");
+ break;
+ default:
+ strCaption += caption; // Use supplied caption
+ }
+
printf("%s: %s\n", caption.c_str(), message.c_str());
- fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
+ fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
return 4;
}
-static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
+static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/)
{
return true;
}
diff --git a/src/protocol.cpp b/src/protocol.cpp
index d6e340e366..23969e5b97 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -6,6 +6,7 @@
#include "protocol.h"
#include "util.h"
#include "netbase.h"
+#include "main.h"
#ifndef WIN32
# include <arpa/inet.h>
@@ -140,6 +141,11 @@ const char* CInv::GetCommand() const
std::string CInv::ToString() const
{
+ if (type == MSG_BLOCK)
+ return strprintf("%s %s", GetCommand(), BlockHashStr(hash).c_str());
+ if (type == MSG_TX)
+ return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,10).c_str());
+
return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str());
}
diff --git a/src/protocol.h b/src/protocol.h
index 36f8b144cd..96fd197ecd 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -134,4 +134,10 @@ class CInv
uint256 hash;
};
+enum
+{
+ MSG_TX = 1,
+ MSG_BLOCK,
+};
+
#endif // __INCLUDED_PROTOCOL_H__
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/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 03aa7af0be..cf35ee2457 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -19,7 +19,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);
-
+
// Setup Caps Lock detection.
ui->passEdit1->installEventFilter(this);
ui->passEdit2->installEventFilter(this);
@@ -108,15 +108,15 @@ void AskPassphraseDialog::accept()
if(model->setWalletEncrypted(true, newpass1))
{
QMessageBox::warning(this, tr("Wallet encrypted"),
- "<qt>" +
+ "<qt>" +
tr("Bitcoin will close now to finish the encryption process. "
"Remember that encrypting your wallet cannot fully protect "
- "your bitcoins from being stolen by malware infecting your computer.") +
- "<br><br><b>" +
+ "your bitcoins from being stolen by malware infecting your computer.") +
+ "<br><br><b>" +
tr("IMPORTANT: Any previous backups you have made of your wallet file "
"should be replaced with the newly generated, encrypted wallet file. "
"For security reasons, previous backups of the unencrypted wallet file "
- "will become useless as soon as you start using the new, encrypted wallet.") +
+ "will become useless as soon as you start using the new, encrypted wallet.") +
"</b></qt>");
QApplication::quit();
}
@@ -221,7 +221,7 @@ bool AskPassphraseDialog::event(QEvent *event)
return QWidget::event(event);
}
-bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
+bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
/* Detect Caps Lock.
* There is no good OS-independent way to check a key state in Qt, but we
@@ -244,5 +244,5 @@ bool AskPassphraseDialog::eventFilter(QObject *, QEvent *event)
}
}
}
- return false;
+ return QDialog::eventFilter(object, event);
}
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index b500ff49bf..338853ce22 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -39,7 +39,7 @@ private:
private slots:
void textChanged();
bool event(QEvent *event);
- bool eventFilter(QObject *, QEvent *event);
+ bool eventFilter(QObject *object, QEvent *event);
};
#endif // ASKPASSPHRASEDIALOG_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index cd1764a53f..dbdfade0b1 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -7,7 +7,6 @@
#include "optionsmodel.h"
#include "guiutil.h"
#include "guiconstants.h"
-
#include "init.h"
#include "ui_interface.h"
#include "qtipcserver.h"
@@ -35,18 +34,18 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets)
static BitcoinGUI *guiref;
static QSplashScreen *splashref;
-static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
+static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
// Message from network thread
if(guiref)
{
bool modal = (style & CClientUIInterface::MODAL);
- // in case of modal message, use blocking connection to wait for user to click OK
- QMetaObject::invokeMethod(guiref, "error",
+ // In case of modal message, use blocking connection to wait for user to click a button
+ QMetaObject::invokeMethod(guiref, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
- Q_ARG(bool, modal));
+ Q_ARG(unsigned int, style));
}
else
{
@@ -55,12 +54,13 @@ static void ThreadSafeMessageBox(const std::string& message, const std::string&
}
}
-static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
+static bool ThreadSafeAskFee(int64 nFeeRequired)
{
if(!guiref)
return false;
if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
return true;
+
bool payFee = false;
QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
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 0d269ea210..3fe86501f6 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -25,6 +25,7 @@
#include "notificator.h"
#include "guiutil.h"
#include "rpcconsole.h"
+#include "ui_interface.h"
#ifdef Q_OS_MAC
#include "macdockiconhandler.h"
@@ -89,7 +90,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Create the toolbars
createToolBars();
- // Create the tray icon (or setup the dock icon)
+ // Create system tray icon and notification
createTrayIcon();
// Create tabs
@@ -176,6 +177,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
// Clicking on "Sign Message" in the receive coins page sends you to the sign message tab
connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString)));
+ // Install event filter to be able to catch status tip events (QEvent::StatusTip)
+ this->installEventFilter(this);
+
gotoOverviewPage();
}
@@ -193,31 +197,36 @@ void BitcoinGUI::createActions()
QActionGroup *tabGroup = new QActionGroup(this);
overviewAction = new QAction(QIcon(":/icons/overview"), tr("&Overview"), this);
- overviewAction->setToolTip(tr("Show general overview of wallet"));
+ overviewAction->setStatusTip(tr("Show general overview of wallet"));
+ overviewAction->setToolTip(overviewAction->statusTip());
overviewAction->setCheckable(true);
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
tabGroup->addAction(overviewAction);
sendCoinsAction = new QAction(QIcon(":/icons/send"), tr("&Send coins"), this);
- sendCoinsAction->setToolTip(tr("Send coins to a Bitcoin address"));
+ sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
+ sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
sendCoinsAction->setCheckable(true);
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
receiveCoinsAction = new QAction(QIcon(":/icons/receiving_addresses"), tr("&Receive coins"), this);
- receiveCoinsAction->setToolTip(tr("Show the list of addresses for receiving payments"));
+ receiveCoinsAction->setStatusTip(tr("Show the list of addresses for receiving payments"));
+ receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
receiveCoinsAction->setCheckable(true);
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
historyAction = new QAction(QIcon(":/icons/history"), tr("&Transactions"), this);
- historyAction->setToolTip(tr("Browse transaction history"));
+ historyAction->setStatusTip(tr("Browse transaction history"));
+ historyAction->setToolTip(historyAction->statusTip());
historyAction->setCheckable(true);
historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
tabGroup->addAction(historyAction);
addressBookAction = new QAction(QIcon(":/icons/address-book"), tr("&Address Book"), this);
- addressBookAction->setToolTip(tr("Edit the list of stored addresses and labels"));
+ addressBookAction->setStatusTip(tr("Edit the list of stored addresses and labels"));
+ addressBookAction->setToolTip(addressBookAction->statusTip());
addressBookAction->setCheckable(true);
addressBookAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5));
tabGroup->addAction(addressBookAction);
@@ -234,33 +243,37 @@ void BitcoinGUI::createActions()
connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
- quitAction->setToolTip(tr("Quit application"));
+ quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin"), this);
- aboutAction->setToolTip(tr("Show information about Bitcoin"));
+ aboutAction->setStatusTip(tr("Show information about Bitcoin"));
aboutAction->setMenuRole(QAction::AboutRole);
aboutQtAction = new QAction(QIcon(":/trolltech/qmessagebox/images/qtlogo-64.png"), tr("About &Qt"), this);
- aboutQtAction->setToolTip(tr("Show information about Qt"));
+ aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
- optionsAction->setToolTip(tr("Modify configuration options for Bitcoin"));
+ optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin"));
optionsAction->setMenuRole(QAction::PreferencesRole);
toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this);
+ toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
- encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
+ encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
encryptWalletAction->setCheckable(true);
backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
- backupWalletAction->setToolTip(tr("Backup wallet to another location"));
+ backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase..."), this);
- changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
+ changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
signMessageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message..."), this);
+ signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
verifyMessageAction = new QAction(QIcon(":/icons/transaction_0"), tr("&Verify message..."), this);
+ verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
- exportAction->setToolTip(tr("Export the data in the current tab to a file"));
+ exportAction->setStatusTip(tr("Export the data in the current tab to a file"));
+ exportAction->setToolTip(exportAction->statusTip());
openRPCConsoleAction = new QAction(QIcon(":/icons/debugwindow"), tr("&Debug window"), this);
- openRPCConsoleAction->setToolTip(tr("Open debugging and diagnostic console"));
+ openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
@@ -338,14 +351,20 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
#endif
if(trayIcon)
{
- trayIcon->setToolTip(tr("Bitcoin client") + QString(" ") + tr("[testnet]"));
+ // Just attach " [testnet]" to the existing tooltip
+ trayIcon->setToolTip(trayIcon->toolTip() + QString(" ") + tr("[testnet]"));
trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
- toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet"));
}
+ toggleHideAction->setIcon(QIcon(":/icons/toolbar_testnet"));
aboutAction->setIcon(QIcon(":/icons/toolbar_testnet"));
}
+ // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
+ // while the client has not yet fully loaded
+ if(trayIcon)
+ createTrayIconMenu();
+
// Keep up to date with client
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
@@ -353,9 +372,10 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
setNumBlocks(clientModel->getNumBlocks(), clientModel->getNumBlocksOfPeers());
connect(clientModel, SIGNAL(numBlocksChanged(int,int)), this, SLOT(setNumBlocks(int,int)));
- // Report errors from network/worker thread
- connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
+ // Receive and report messages from network/worker thread
+ connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
+ overviewPage->setClientModel(clientModel);
rpcConsole->setClientModel(clientModel);
addressBookPage->setOptionsModel(clientModel->getOptionsModel());
receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
@@ -367,13 +387,12 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel)
this->walletModel = walletModel;
if(walletModel)
{
- // Report errors from wallet thread
- connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
+ // Receive and report messages from wallet thread
+ connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
// Put transaction list in tabs
transactionView->setModel(walletModel);
-
- overviewPage->setModel(walletModel);
+ overviewPage->setWalletModel(walletModel);
addressBookPage->setModel(walletModel->getAddressTableModel());
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
sendCoinsPage->setModel(walletModel);
@@ -393,16 +412,26 @@ void BitcoinGUI::setWalletModel(WalletModel *walletModel)
void BitcoinGUI::createTrayIcon()
{
- QMenu *trayIconMenu;
#ifndef Q_OS_MAC
trayIcon = new QSystemTrayIcon(this);
- trayIconMenu = new QMenu(this);
- trayIcon->setContextMenu(trayIconMenu);
+
trayIcon->setToolTip(tr("Bitcoin client"));
trayIcon->setIcon(QIcon(":/icons/toolbar"));
+ trayIcon->show();
+#endif
+
+ notificator = new Notificator(qApp->applicationName(), trayIcon);
+}
+
+void BitcoinGUI::createTrayIconMenu()
+{
+ QMenu *trayIconMenu;
+#ifndef Q_OS_MAC
+ trayIconMenu = new QMenu(this);
+ trayIcon->setContextMenu(trayIconMenu);
+
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
- trayIcon->show();
#else
// Note: On Mac, the dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
@@ -424,8 +453,6 @@ void BitcoinGUI::createTrayIcon()
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
#endif
-
- notificator = new Notificator(qApp->applicationName(), trayIcon);
}
#ifndef Q_OS_MAC
@@ -472,8 +499,12 @@ void BitcoinGUI::setNumConnections(int count)
void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
{
+ // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text)
+ 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);
@@ -481,41 +512,41 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
return;
}
- QString strStatusBarWarnings = clientModel->getStatusBarWarnings();
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);
- if (strStatusBarWarnings.isEmpty())
- {
- progressBarLabel->setText(tr(clientModel->isImporting() ? "Importing blocks..." : "Synchronizing with network..."));
- progressBarLabel->setVisible(true);
- progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
- progressBar->setMaximum(nTotalBlocks);
- progressBar->setValue(count);
- progressBar->setVisible(true);
- }
+ 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
{
- if (strStatusBarWarnings.isEmpty())
- progressBarLabel->setVisible(false);
+ progressBarLabel->setVisible(false);
progressBar->setVisible(false);
- tooltip = tr("Downloaded %1 blocks of transaction history.").arg(count);
- }
-
- // Override progressBarLabel text and hide progress bar, when we have warnings to display
- if (!strStatusBarWarnings.isEmpty())
- {
- progressBarLabel->setText(strStatusBarWarnings);
- progressBarLabel->setVisible(true);
- progressBar->setVisible(false);
+ tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
}
QDateTime lastBlockDate = clientModel->getLastBlockDate();
@@ -575,15 +606,50 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
progressBar->setToolTip(tooltip);
}
-void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
+void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style)
{
- // Report errors from network/worker thread
- if(modal)
- {
- QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
- } else {
- notificator->notify(Notificator::Critical, title, message);
+ QString strTitle = tr("Bitcoin") + " - ";
+ // Default to information icon
+ int nMBoxIcon = QMessageBox::Information;
+ int nNotifyIcon = Notificator::Information;
+
+ // Check for usage of predefined title
+ switch (style) {
+ case CClientUIInterface::MSG_ERROR:
+ strTitle += tr("Error");
+ break;
+ case CClientUIInterface::MSG_WARNING:
+ strTitle += tr("Warning");
+ break;
+ case CClientUIInterface::MSG_INFORMATION:
+ strTitle += tr("Information");
+ break;
+ default:
+ strTitle += title; // Use supplied title
+ }
+
+ // Check for error/warning icon
+ if (style & CClientUIInterface::ICON_ERROR) {
+ nMBoxIcon = QMessageBox::Critical;
+ nNotifyIcon = Notificator::Critical;
+ }
+ else if (style & CClientUIInterface::ICON_WARNING) {
+ nMBoxIcon = QMessageBox::Warning;
+ nNotifyIcon = Notificator::Warning;
+ }
+
+ // Display message
+ if (style & CClientUIInterface::MODAL) {
+ // Check for buttons, use OK as default, if none was supplied
+ QMessageBox::StandardButton buttons;
+ if (!(buttons = (QMessageBox::StandardButton)(style & CClientUIInterface::BTN_MASK)))
+ buttons = QMessageBox::Ok;
+
+ QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons);
+ mBox.exec();
}
+ else
+ notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
}
void BitcoinGUI::changeEvent(QEvent *e)
@@ -622,11 +688,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);
@@ -763,6 +827,18 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
event->acceptProposedAction();
}
+bool BitcoinGUI::eventFilter(QObject *object, QEvent *event)
+{
+ // Catch status tip events
+ if (event->type() == QEvent::StatusTip)
+ {
+ // Prevent adding text from setStatusTip(), if we currently use the status bar for displaying other stuff
+ if (progressBarLabel->isVisible() && progressBar->isVisible())
+ return true;
+ }
+ return QMainWindow::eventFilter(object, event);
+}
+
void BitcoinGUI::handleURI(QString strURI)
{
// URI has to be valid
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index c67e887c0f..3faf6d948c 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -52,6 +52,7 @@ protected:
void closeEvent(QCloseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
+ bool eventFilter(QObject *object, QEvent *event);
private:
ClientModel *clientModel;
@@ -104,8 +105,10 @@ private:
void createMenuBar();
/** Create the toolbars */
void createToolBars();
- /** Create system tray (notification) icon */
+ /** Create system tray icon and notification */
void createTrayIcon();
+ /** Create system tray menu (or setup the dock menu) */
+ void createTrayIconMenu();
public slots:
/** Set number of connections shown in the UI */
@@ -118,8 +121,13 @@ public slots:
*/
void setEncryptionStatus(int status);
- /** Notify the user of an error in the network or transaction handling code. */
- void error(const QString &title, const QString &message, bool modal);
+ /** Notify the user of an event from the core network or transaction handling code.
+ @param[in] title the message box / notification title
+ @param[in] message the displayed text
+ @param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes)
+ @see CClientUIInterface::MessageBoxFlags
+ */
+ void message(const QString &title, const QString &message, unsigned int style);
/** Asks the user whether to pay the transaction fee or to cancel the transaction.
It is currently not possible to pass a return value to another thread through
BlockingQueuedConnection, so an indirected pointer is used.
@@ -172,8 +180,8 @@ private slots:
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
void showNormalIfMinimized(bool fToggleHidden = false);
- /** simply calls showNormalIfMinimized(true) for use in SLOT() macro */
+ /** Simply calls showNormalIfMinimized(true) for use in SLOT() macro */
void toggleHidden();
};
-#endif
+#endif // BITCOINGUI_H
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index b92a26c4a4..497c05976b 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -13,28 +13,33 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"rpcuser=bitcoinrpc\n"
"rpcpassword=%s\n"
"(you do not need to remember this password)\n"
+"The username and password MUST NOT be the same.\n"
"If the file does not exist, create it with owner-readable-only file "
"permissions.\n"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:"
"@STRENGTH)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"An error occurred while setting up the RPC port %u for listening on IPv4: %s"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"An error occurred while setting up the RPC port %u for listening on IPv6, "
"falling back to IPv4: %s"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"An error occurred while setting up the RPC port %u for listening on IPv4: %s"),
+"Bind to given address and always listen on it. Use [host]:port notation for "
+"IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Cannot obtain a lock on data directory %s. Bitcoin is probably already "
+"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)"),
+"Error initializing database environment %s! To recover, BACKUP THAT "
+"DIRECTORY, then remove everything from it except for wallet.dat."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error: The transaction was rejected. This might happen if some of the coins "
+"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."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: This transaction requires a transaction fee of at least %s because of "
-"its amount, complexity, or use of recently received funds "),
+"its amount, complexity, or use of recently received funds!"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
@@ -47,6 +52,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Set maximum size of high-priority/low-fee transactions in bytes (default: "
"27000)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"This is a pre-release test build - use at your own risk - do not use for "
+"mining or merchant applications"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to bind to %s on this computer. Bitcoin is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: -paytxfee is set very high! This is the transaction fee you will "
@@ -58,6 +66,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Please check that your computer's date and time are correct! If "
"your clock is wrong Bitcoin will not work properly."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Warning: error reading wallet.dat! All keys read correctly, but transaction "
+"data or address book entries might be missing or incorrect."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as "
+"wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect "
+"you should restore from a backup."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"You must set rpcpassword=<password> in the configuration file:\n"
"%s\n"
"If the file does not exist, create it with owner-readable-only file "
@@ -67,7 +82,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 i
QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"),
QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Bind to given address. Use [host]:port notation for IPv6"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"),
QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"),
@@ -87,8 +102,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed!"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"),
@@ -98,8 +113,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"),
QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"),
QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-6, default: 1)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Importing blockchain data file."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Importing bootstrap blockchain data file."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Importing blocks from block database..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000?.dat file"),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"),
@@ -120,6 +134,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information. Implies a
QT_TRANSLATE_NOOP("bitcoin-core", "Output extra network debugging information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"),
QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild blockchain index from current blk000??.dat files"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"),
@@ -133,7 +148,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (default: 25)"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Set database disk log size in megabytes (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: 250000)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: 0)"),
@@ -157,7 +171,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default:
QT_TRANSLATE_NOOP("bitcoin-core", "Use proxy to reach tor hidden services (default: same as -proxy)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"),
QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Verifying database integrity..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"),
+QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"),
}; \ No newline at end of file
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 990b364a94..ce112803f8 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -84,13 +84,11 @@ void ClientModel::updateAlert(const QString &hash, int status)
CAlert alert = CAlert::getAlertByHash(hash_256);
if(!alert.IsNull())
{
- emit error(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), false);
+ emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
}
}
- // Emit a numBlocksChanged when the status message changes,
- // so that the view recomputes and updates the status bar.
- emit numBlocksChanged(getNumBlocks(), getNumBlocksOfPeers());
+ emit alertsChanged(getStatusBarWarnings());
}
bool ClientModel::isTestNet() const
@@ -103,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
@@ -133,6 +135,11 @@ QString ClientModel::formatBuildDate() const
return QString::fromStdString(CLIENT_DATE);
}
+bool ClientModel::isReleaseVersion() const
+{
+ return CLIENT_VERSION_IS_RELEASE;
+}
+
QString ClientModel::clientName() const
{
return QString::fromStdString(CLIENT_NAME);
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 926390a07a..1afccb7859 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
@@ -42,6 +49,7 @@ public:
QString formatFullVersion() const;
QString formatBuildDate() const;
+ bool isReleaseVersion() const;
QString clientName() const;
QString formatClientStartupTime() const;
@@ -60,9 +68,10 @@ private:
signals:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, int countOfPeers);
+ void alertsChanged(const QString &warnings);
- //! Asynchronous error notification
- void error(const QString &title, const QString &message, bool modal);
+ //! Asynchronous message notification
+ void message(const QString &title, const QString &message, unsigned int style);
public slots:
void updateTimer();
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/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 98cb63e9ff..4c4dec6c9c 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -13,282 +13,303 @@
<property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
+ <layout class="QVBoxLayout" name="topLayout">
<item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
+ <widget class="QLabel" name="labelAlerts">
+ <property name="visible">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000
+</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>3</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
- <widget class="QFrame" name="frame">
- <property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
<item>
- <widget class="QLabel" name="label_5">
- <property name="font">
- <font>
- <pointsize>11</pointsize>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Wallet</string>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Wallet</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelWalletStatus">
+ <property name="toolTip">
+ <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLabel { color: red; }</string>
+ </property>
+ <property name="text">
+ <string notr="true">(out of sync)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
<item>
- <widget class="QLabel" name="labelWalletStatus">
- <property name="toolTip">
- <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
- </property>
- <property name="styleSheet">
- <string notr="true">QLabel { color: red; }</string>
- </property>
- <property name="text">
- <string notr="true">(out of sync)</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QFormLayout" name="formLayout_2">
- <property name="fieldGrowthPolicy">
- <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
- </property>
- <property name="horizontalSpacing">
- <number>12</number>
- </property>
- <property name="verticalSpacing">
- <number>12</number>
- </property>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Balance:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="labelBalance">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="toolTip">
- <string>Your current balance</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Unconfirmed:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelUnconfirmed">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="toolTip">
- <string>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Number of transactions:</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLabel" name="labelNumTransactions">
- <property name="toolTip">
- <string>Total number of transactions in wallet</string>
- </property>
- <property name="text">
- <string notr="true">0</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="labelImmatureText">
- <property name="text">
- <string>Immature:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="labelImmature">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="toolTip">
- <string>Mined balance that has not yet matured</string>
- </property>
- <property name="text">
- <string notr="true">0 BTC</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>12</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>12</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Balance:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="labelBalance">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Your current balance</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Unconfirmed:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="labelUnconfirmed">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Number of transactions:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="labelNumTransactions">
+ <property name="toolTip">
+ <string>Total number of transactions in wallet</string>
+ </property>
+ <property name="text">
+ <string notr="true">0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="labelImmatureText">
+ <property name="text">
+ <string>Immature:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="labelImmature">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="toolTip">
+ <string>Mined balance that has not yet matured</string>
+ </property>
+ <property name="text">
+ <string notr="true">0 BTC</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
- </layout>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <widget class="QFrame" name="frame_2">
- <property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Raised</enum>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QFrame" name="frame_2">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
<item>
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>&lt;b&gt;Recent transactions&lt;/b&gt;</string>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&lt;b&gt;Recent transactions&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelTransactionsStatus">
+ <property name="toolTip">
+ <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLabel { color: red; }</string>
+ </property>
+ <property name="text">
+ <string notr="true">(out of sync)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
<item>
- <widget class="QLabel" name="labelTransactionsStatus">
- <property name="toolTip">
- <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
- </property>
+ <widget class="QListView" name="listTransactions">
<property name="styleSheet">
- <string notr="true">QLabel { color: red; }</string>
+ <string notr="true">QListView { background: transparent; }</string>
</property>
- <property name="text">
- <string notr="true">(out of sync)</string>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
</property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
</property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
</property>
- </spacer>
+ </widget>
</item>
</layout>
- </item>
- <item>
- <widget class="QListView" name="listTransactions">
- <property name="styleSheet">
- <string notr="true">QListView { background: transparent; }</string>
- </property>
- <property name="frameShape">
- <enum>QFrame::NoFrame</enum>
- </property>
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::NoSelection</enum>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
</layout>
</item>
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/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index ee9967e15d..c70ea652de 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -300,17 +300,17 @@ This product includes software developed by the OpenSSL Project for use in the O
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+257"/>
+ <location filename="../bitcoingui.cpp" line="+266"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+237"/>
+ <location line="+241"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-299"/>
+ <location line="-309"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -320,7 +320,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Show general overview of wallet</translation>
</message>
<message>
- <location line="+17"/>
+ <location line="+20"/>
<source>&amp;Transactions</source>
<translation>&amp;Transactions</translation>
</message>
@@ -330,7 +330,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Browse transaction history</translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+6"/>
<source>&amp;Address Book</source>
<translation>&amp;Address Book</translation>
</message>
@@ -340,7 +340,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Edit the list of stored addresses and labels</translation>
</message>
<message>
- <location line="-13"/>
+ <location line="-15"/>
<source>&amp;Receive coins</source>
<translation>&amp;Receive coins</translation>
</message>
@@ -350,12 +350,12 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Show the list of addresses for receiving payments</translation>
</message>
<message>
- <location line="-7"/>
+ <location line="-8"/>
<source>&amp;Send coins</source>
<translation>&amp;Send coins</translation>
</message>
<message>
- <location line="+35"/>
+ <location line="+39"/>
<source>E&amp;xit</source>
<translation>E&amp;xit</translation>
</message>
@@ -385,7 +385,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>&amp;Options...</translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+5"/>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Encrypt Wallet...</translation>
</message>
@@ -399,8 +399,18 @@ This product includes software developed by the OpenSSL Project for use in the O
<source>&amp;Change Passphrase...</source>
<translation>&amp;Change Passphrase...</translation>
</message>
+ <message>
+ <location line="+246"/>
+ <source>Importing blocks from disk...</source>
+ <translation>Importing blocks from disk...</translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Reindexing blocks on disk...</translation>
+ </message>
<message numerus="yes">
- <location line="+241"/>
+ <location line="+10"/>
<source>~%n block(s) remaining</source>
<translation>
<numerusform>~%n block remaining</numerusform>
@@ -408,37 +418,27 @@ This product includes software developed by the OpenSSL Project for use in the O
</translation>
</message>
<message>
- <location line="+6"/>
- <source>Downloaded %1 of %2 blocks of transaction history (%3% done).</source>
- <translation>Downloaded %1 of %2 blocks of transaction history (%3% done).</translation>
- </message>
- <message>
- <location line="-242"/>
+ <location line="-252"/>
<source>&amp;Export...</source>
<translation>&amp;Export...</translation>
</message>
<message>
- <location line="-58"/>
+ <location line="-65"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
<message>
- <location line="+45"/>
+ <location line="+49"/>
<source>Modify configuration options for Bitcoin</source>
<translation>Modify configuration options for Bitcoin</translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+17"/>
<source>Export the data in the current tab to a file</source>
<translation>Export the data in the current tab to a file</translation>
</message>
<message>
- <location line="-10"/>
- <source>Encrypt or decrypt wallet</source>
- <translation>Encrypt or decrypt wallet</translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="-9"/>
<source>Backup wallet to another location</source>
<translation>Backup wallet to another location</translation>
</message>
@@ -448,7 +448,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Change the passphrase used for wallet encryption</translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+9"/>
<source>&amp;Debug window</source>
<translation>&amp;Debug window</translation>
</message>
@@ -458,12 +458,12 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Open debugging and diagnostic console</translation>
</message>
<message>
- <location line="-5"/>
+ <location line="-7"/>
<source>&amp;Verify message...</source>
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="-186"/>
+ <location line="-196"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
@@ -473,7 +473,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Wallet</translation>
</message>
<message>
- <location line="+168"/>
+ <location line="+176"/>
<source>&amp;About Bitcoin</source>
<translation>&amp;About Bitcoin</translation>
</message>
@@ -483,7 +483,27 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>&amp;Show / Hide</translation>
</message>
<message>
- <location line="+39"/>
+ <location line="+1"/>
+ <source>Show or hide the main Window</source>
+ <translation>Show or hide the main Window</translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Encrypt the private keys that belong to your wallet</translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Sign messages with your Bitcoin addresses to prove you own them</translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation>
+ </message>
+ <message>
+ <location line="+31"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
@@ -509,12 +529,11 @@ This product includes software developed by the OpenSSL Project for use in the O
</message>
<message>
<location line="+13"/>
- <location line="+9"/>
+ <location line="+10"/>
<source>[testnet]</source>
<translation>[testnet]</translation>
</message>
<message>
- <location line="+0"/>
<location line="+60"/>
<source>Bitcoin client</source>
<translation>Bitcoin client</translation>
@@ -528,12 +547,22 @@ This product includes software developed by the OpenSSL Project for use in the O
</translation>
</message>
<message>
- <location line="+40"/>
- <source>Downloaded %1 blocks of transaction history.</source>
- <translation>Downloaded %1 blocks of transaction history.</translation>
+ <location line="+45"/>
+ <source>Processed %1 of %2 blocks of transaction history (%3% done).</source>
+ <translation>Processed %1 of %2 blocks of transaction history (%3% done).</translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Processed %1 blocks of transaction history.</source>
+ <translation>Processed %1 blocks of transaction history.</translation>
+ </message>
+ <message>
+ <location line="+107"/>
+ <source>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?</source>
+ <translation>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?</translation>
</message>
<message numerus="yes">
- <location line="+22"/>
+ <location line="-93"/>
<source>%n second(s) ago</source>
<translation>
<numerusform>%n second ago</numerusform>
@@ -580,12 +609,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>Last received block was generated %1.</translation>
</message>
<message>
- <location line="+59"/>
- <source>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?</source>
- <translation>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?</translation>
- </message>
- <message>
- <location line="+5"/>
+ <location line="+62"/>
<source>Confirm transaction fee</source>
<translation>Confirm transaction fee</translation>
</message>
@@ -614,13 +638,13 @@ Address: %4
</message>
<message>
<location line="+100"/>
- <location line="+15"/>
+ <location line="+27"/>
<source>URI handling</source>
<translation>URI handling</translation>
</message>
<message>
- <location line="-15"/>
- <location line="+15"/>
+ <location line="-27"/>
+ <location line="+27"/>
<source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<translation>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation>
</message>
@@ -813,16 +837,6 @@ Address: %4
<translation>&amp;Start Bitcoin on system login</translation>
</message>
<message>
- <location line="+7"/>
- <source>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.</source>
- <translation>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.</translation>
- </message>
- <message>
- <location line="+3"/>
- <source>&amp;Detach databases at shutdown</source>
- <translation>&amp;Detach databases at shutdown</translation>
- </message>
- <message>
<location line="+21"/>
<source>&amp;Network</source>
<translation>&amp;Network</translation>
@@ -958,7 +972,7 @@ Address: %4
<translation>default</translation>
</message>
<message>
- <location line="+147"/>
+ <location line="+146"/>
<location line="+9"/>
<source>Warning</source>
<translation>Warning</translation>
@@ -983,7 +997,7 @@ Address: %4
<translation>Form</translation>
</message>
<message>
- <location line="+33"/>
+ <location line="+52"/>
<location line="+183"/>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation>
@@ -1039,7 +1053,7 @@ Address: %4
<translation>Total number of transactions in wallet</translation>
</message>
<message>
- <location filename="../overviewpage.cpp" line="+112"/>
+ <location filename="../overviewpage.cpp" line="+115"/>
<location line="+1"/>
<source>out of sync</source>
<translation>out of sync</translation>
@@ -1120,7 +1134,7 @@ Address: %4
<location line="+53"/>
<location line="+23"/>
<location line="+23"/>
- <location filename="../rpcconsole.cpp" line="+348"/>
+ <location filename="../rpcconsole.cpp" line="+349"/>
<source>N/A</source>
<translation>N/A</translation>
</message>
@@ -1351,8 +1365,8 @@ Address: %4
</message>
<message>
<location line="+5"/>
- <source>Error: Transaction creation failed.</source>
- <translation>Error: Transaction creation failed.</translation>
+ <source>Error: Transaction creation failed!</source>
+ <translation>Error: Transaction creation failed!</translation>
</message>
<message>
<location line="+5"/>
@@ -1378,23 +1392,23 @@ Address: %4
<translation>Pay &amp;To:</translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+34"/>
+ <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
+ <translation>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
+ </message>
+ <message>
+ <location line="+60"/>
<location filename="../sendcoinsentry.cpp" line="+25"/>
<source>Enter a label for this address to add it to your address book</source>
<translation>Enter a label for this address to add it to your address book</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="-78"/>
<source>&amp;Label:</source>
<translation>&amp;Label:</translation>
</message>
<message>
- <location line="+18"/>
- <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source>
- <translation>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation>
- </message>
- <message>
- <location line="+10"/>
+ <location line="+28"/>
<source>Choose address from address book</source>
<translation>Choose address from address book</translation>
</message>
@@ -1757,7 +1771,7 @@ Address: %4
<translation>Transaction</translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+3"/>
<source>Inputs</source>
<translation>Inputs</translation>
</message>
@@ -1777,7 +1791,7 @@ Address: %4
<translation>false</translation>
</message>
<message>
- <location line="-211"/>
+ <location line="-209"/>
<source>, has not been successfully broadcast yet</source>
<translation>, has not been successfully broadcast yet</translation>
</message>
@@ -2099,32 +2113,32 @@ Address: %4
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+71"/>
+ <location filename="../bitcoinstrings.cpp" line="+86"/>
<source>Bitcoin version</source>
<translation>Bitcoin version</translation>
</message>
<message>
- <location line="+82"/>
+ <location line="+81"/>
<source>Usage:</source>
<translation>Usage:</translation>
</message>
<message>
- <location line="-25"/>
+ <location line="-24"/>
<source>Send command to -server or bitcoind</source>
<translation>Send command to -server or bitcoind</translation>
</message>
<message>
- <location line="-19"/>
+ <location line="-20"/>
<source>List commands</source>
<translation>List commands</translation>
</message>
<message>
- <location line="-11"/>
+ <location line="-10"/>
<source>Get help for a command</source>
<translation>Get help for a command</translation>
</message>
<message>
- <location line="+20"/>
+ <location line="+19"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
@@ -2139,7 +2153,7 @@ Address: %4
<translation>Specify pid file (default: bitcoind.pid)</translation>
</message>
<message>
- <location line="-47"/>
+ <location line="-46"/>
<source>Generate coins</source>
<translation>Generate coins</translation>
</message>
@@ -2149,21 +2163,16 @@ Address: %4
<translation>Don&apos;t generate coins</translation>
</message>
<message>
- <location line="+60"/>
+ <location line="+59"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
<message>
- <location line="-8"/>
+ <location line="-7"/>
<source>Set database cache size in megabytes (default: 25)</source>
<translation>Set database cache size in megabytes (default: 25)</translation>
</message>
<message>
- <location line="+1"/>
- <source>Set database disk log size in megabytes (default: 100)</source>
- <translation>Set database disk log size in megabytes (default: 100)</translation>
- </message>
- <message>
<location line="-26"/>
<source>Listen for connections on &lt;port&gt; (default: 8333 or testnet: 18333)</source>
<translation>Listen for connections on &lt;port&gt; (default: 8333 or testnet: 18333)</translation>
@@ -2174,86 +2183,116 @@ Address: %4
<translation>Maintain at most &lt;n&gt; connections to peers (default: 125)</translation>
</message>
<message>
- <location line="-33"/>
+ <location line="-32"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
- <location line="+64"/>
+ <location line="+63"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="-75"/>
- <source>Bind to given address. Use [host]:port notation for IPv6</source>
- <translation>Bind to given address. Use [host]:port notation for IPv6</translation>
- </message>
- <message>
- <location line="+77"/>
+ <location line="+2"/>
<source>Threshold for disconnecting misbehaving peers (default: 100)</source>
<translation>Threshold for disconnecting misbehaving peers (default: 100)</translation>
</message>
<message>
- <location line="-104"/>
+ <location line="-113"/>
<source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source>
<translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation>
</message>
<message>
- <location line="-19"/>
+ <location line="-26"/>
<source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source>
<translation>An error occurred while setting up the RPC port %u for listening on IPv4: %s</translation>
</message>
<message>
- <location line="+5"/>
- <source>Detach block and address databases. Increases shutdown time (default: 0)</source>
- <translation>Detach block and address databases. Increases shutdown time (default: 0)</translation>
- </message>
- <message>
- <location line="+12"/>
+ <location line="+24"/>
<source>Listen for JSON-RPC connections on &lt;port&gt; (default: 8332 or testnet: 18332)</source>
<translation>Listen for JSON-RPC connections on &lt;port&gt; (default: 8332 or testnet: 18332)</translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+34"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="+36"/>
- <source>Importing blockchain data file.</source>
- <translation>Importing blockchain data file.</translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Importing bootstrap blockchain data file.</source>
- <translation>Importing bootstrap blockchain data file.</translation>
- </message>
- <message>
- <location line="+23"/>
+ <location line="+60"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
<message>
- <location line="+33"/>
+ <location line="+32"/>
<source>Use the test network</source>
<translation>Use the test network</translation>
</message>
<message>
- <location line="-92"/>
+ <location line="-91"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
<translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-72"/>
+ <source>%s, you must set a rpcpassword in the configuration file:
+ %s
+It is recommended you use the following random password:
+rpcuser=bitcoinrpc
+rpcpassword=%s
+(you do not need to remember this password)
+The username and password MUST NOT be the same.
+If the file does not exist, create it with owner-readable-only file permissions.
+</source>
+ <translation>%s, you must set a rpcpassword in the configuration file:
+ %s
+It is recommended you use the following random password:
+rpcuser=bitcoinrpc
+rpcpassword=%s
+(you do not need to remember this password)
+The username and password MUST NOT be the same.
+If the file does not exist, create it with owner-readable-only file permissions.</translation>
+ </message>
+ <message>
+ <location line="+15"/>
<source>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</source>
<translation>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+3"/>
+ <source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source>
+ <translation>Bind to given address and always listen on it. Use [host]:port notation for IPv6</translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</source>
+ <translation>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat.</source>
+ <translation>Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat.</translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>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.</source>
+ <translation>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.</translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</source>
+ <translation>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</translation>
+ </message>
+ <message>
+ <location line="+11"/>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</source>
<translation>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</translation>
</message>
<message>
+ <location line="+3"/>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation>
+ </message>
+ <message>
<location line="+5"/>
<source>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source>
<translation>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</translation>
@@ -2269,7 +2308,22 @@ Address: %4
<translation>Warning: Please check that your computer&apos;s date and time are correct! If your clock is wrong Bitcoin will not work properly.</translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+3"/>
+ <source>Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <translation>Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
+ <translation>Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup.</translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <source>Attempt to recover private keys from a corrupt wallet.dat</source>
+ <translation>Attempt to recover private keys from a corrupt wallet.dat</translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Block creation options:</source>
<translation>Block creation options:</translation>
</message>
@@ -2284,7 +2338,17 @@ Address: %4
<translation>Discover own IP address (default: 1 when listening and no -externalip)</translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+8"/>
+ <source>Error: Transaction creation failed!</source>
+ <translation>Error: Transaction creation failed!</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Error: Wallet locked, unable to create transaction!</source>
+ <translation>Error: Wallet locked, unable to create transaction!</translation>
+ </message>
+ <message>
+ <location line="+2"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
@@ -2294,7 +2358,12 @@ Address: %4
<translation>Find peers using DNS lookup (default: 1 unless -connect)</translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+6"/>
+ <source>Importing blocks from block database...</source>
+ <translation>Importing blocks from block database...</translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Invalid -tor address: &apos;%s&apos;</source>
<translation>Invalid -tor address: &apos;%s&apos;</translation>
</message>
@@ -2329,6 +2398,11 @@ Address: %4
<translation>Prepend debug output with timestamp</translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Rebuild blockchain index from current blk000??.dat files</source>
+ <translation>Rebuild blockchain index from current blk000??.dat files</translation>
+ </message>
+ <message>
<location line="+4"/>
<source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
<translation>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</translation>
@@ -2349,7 +2423,7 @@ Address: %4
<translation>Send trace/debug info to debugger</translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+6"/>
<source>Set maximum block size in bytes (default: 250000)</source>
<translation>Set maximum block size in bytes (default: 250000)</translation>
</message>
@@ -2389,6 +2463,11 @@ Address: %4
<translation>Username for JSON-RPC connections</translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Verifying database integrity...</source>
+ <translation>Verifying database integrity...</translation>
+ </message>
+ <message>
<location line="+2"/>
<source>Warning: Disk space is low!</source>
<translation>Warning: Disk space is low!</translation>
@@ -2399,12 +2478,17 @@ Address: %4
<translation>Warning: This version is obsolete, upgrade required!</translation>
</message>
<message>
- <location line="-41"/>
+ <location line="+1"/>
+ <source>wallet.dat corrupt, salvage failed</source>
+ <translation>wallet.dat corrupt, salvage failed</translation>
+ </message>
+ <message>
+ <location line="-43"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-52"/>
+ <location line="-51"/>
<source>Allow JSON-RPC connections from specified IP address</source>
<translation>Allow JSON-RPC connections from specified IP address</translation>
</message>
@@ -2414,12 +2498,12 @@ Address: %4
<translation>Send commands to node running on &lt;ip&gt; (default: 127.0.0.1)</translation>
</message>
<message>
- <location line="-91"/>
+ <location line="-101"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+114"/>
+ <location line="+123"/>
<source>Upgrade wallet to latest format</source>
<translation>Upgrade wallet to latest format</translation>
</message>
@@ -2429,7 +2513,7 @@ Address: %4
<translation>Set key pool size to &lt;n&gt; (default: 100)</translation>
</message>
<message>
- <location line="-14"/>
+ <location line="-13"/>
<source>Rescan the block chain for missing wallet transactions</source>
<translation>Rescan the block chain for missing wallet transactions</translation>
</message>
@@ -2444,7 +2528,7 @@ Address: %4
<translation>How thorough the block verification is (0-6, default: 1)</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+2"/>
<source>Imports blocks from external blk000?.dat file</source>
<translation>Imports blocks from external blk000?.dat file</translation>
</message>
@@ -2454,7 +2538,7 @@ Address: %4
<translation>Use OpenSSL (https) for JSON-RPC connections</translation>
</message>
<message>
- <location line="-21"/>
+ <location line="-20"/>
<source>Server certificate file (default: server.cert)</source>
<translation>Server certificate file (default: server.cert)</translation>
</message>
@@ -2464,32 +2548,27 @@ Address: %4
<translation>Server private key (default: server.pem)</translation>
</message>
<message>
- <location line="-116"/>
+ <location line="-130"/>
<source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source>
<translation>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</translation>
</message>
<message>
- <location line="+128"/>
+ <location line="+141"/>
<source>This help message</source>
<translation>This help message</translation>
</message>
<message>
- <location line="-120"/>
- <source>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</source>
- <translation>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</translation>
- </message>
- <message>
- <location line="+46"/>
+ <location line="-73"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="+77"/>
+ <location line="+76"/>
<source>Unable to bind to %s on this computer (bind returned error %d, %s)</source>
<translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation>
</message>
<message>
- <location line="-69"/>
+ <location line="-68"/>
<source>Connect through socks proxy</source>
<translation>Connect through socks proxy</translation>
</message>
@@ -2499,12 +2578,12 @@ Address: %4
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+42"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
<message>
- <location line="-26"/>
+ <location line="-25"/>
<source>Error loading blkindex.dat</source>
<translation>Error loading blkindex.dat</translation>
</message>
@@ -2529,7 +2608,7 @@ Address: %4
<translation>Error loading wallet.dat</translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+18"/>
<source>Invalid -proxy address: &apos;%s&apos;</source>
<translation>Invalid -proxy address: &apos;%s&apos;</translation>
</message>
@@ -2544,7 +2623,7 @@ Address: %4
<translation>Unknown -socks proxy version requested: %i</translation>
</message>
<message>
- <location line="-74"/>
+ <location line="-73"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -2554,42 +2633,22 @@ Address: %4
<translation>Cannot resolve -externalip address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+29"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-15"/>
+ <location line="-14"/>
<source>Error: could not start node</source>
<translation>Error: could not start node</translation>
</message>
<message>
- <location line="-1"/>
- <source>Error: Wallet locked, unable to create transaction </source>
- <translation>Error: Wallet locked, unable to create transaction </translation>
- </message>
- <message>
- <location line="-56"/>
- <source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds </source>
- <translation>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds </translation>
- </message>
- <message>
- <location line="+55"/>
- <source>Error: Transaction creation failed </source>
- <translation>Error: Transaction creation failed </translation>
- </message>
- <message>
- <location line="+42"/>
+ <location line="+40"/>
<source>Sending...</source>
<translation>Sending...</translation>
</message>
<message>
- <location line="-101"/>
- <source>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.</source>
- <translation>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.</translation>
- </message>
- <message>
- <location line="+77"/>
+ <location line="-25"/>
<source>Invalid amount</source>
<translation>Invalid amount</translation>
</message>
@@ -2604,17 +2663,17 @@ Address: %4
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-44"/>
<source>Add a node to connect to and attempt to keep the connection open</source>
<translation>Add a node to connect to and attempt to keep the connection open</translation>
</message>
<message>
- <location line="-18"/>
+ <location line="-25"/>
<source>Unable to bind to %s on this computer. Bitcoin is probably already running.</source>
<translation>Unable to bind to %s on this computer. Bitcoin is probably already running.</translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+54"/>
<source>Find peers using internet relay chat (default: 0)</source>
<translation>Find peers using internet relay chat (default: 0)</translation>
</message>
@@ -2624,12 +2683,12 @@ Address: %4
<translation>Fee per KB to add to transactions you send</translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+18"/>
<source>Loading wallet...</source>
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-39"/>
+ <location line="-38"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -2654,31 +2713,12 @@ Address: %4
<translation>Done loading</translation>
</message>
<message>
- <location line="+64"/>
+ <location line="+63"/>
<source>To use the %s option</source>
<translation>To use the %s option</translation>
</message>
<message>
- <location line="-139"/>
- <source>%s, you must set a rpcpassword in the configuration file:
- %s
-It is recommended you use the following random password:
-rpcuser=bitcoinrpc
-rpcpassword=%s
-(you do not need to remember this password)
-If the file does not exist, create it with owner-readable-only file permissions.
-</source>
- <translation>%s, you must set a rpcpassword in the configuration file:
- %s
-It is recommended you use the following random password:
-rpcuser=bitcoinrpc
-rpcpassword=%s
-(you do not need to remember this password)
-If the file does not exist, create it with owner-readable-only file permissions.
-</translation>
- </message>
- <message>
- <location line="+80"/>
+ <location line="-58"/>
<source>Error</source>
<translation>Error</translation>
</message>
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/notificator.h b/src/qt/notificator.h
index abb47109b3..833b52cb15 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -46,11 +46,11 @@ public slots:
private:
QWidget *parent;
enum Mode {
- None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
- Freedesktop, /**< Use DBus org.freedesktop.Notifications */
- QSystemTray, /**< Use QSystemTray::showMessage */
+ None, /**< Ignore informational notifications, and show a modal pop-up dialog for Critical notifications. */
+ Freedesktop, /**< Use DBus org.freedesktop.Notifications */
+ QSystemTray, /**< Use QSystemTray::showMessage */
Growl12, /**< Use the Growl 1.2 notification system (Mac only) */
- Growl13 /**< Use the Growl 1.3 notification system (Mac only) */
+ Growl13 /**< Use the Growl 1.3 notification system (Mac only) */
};
QString programName;
Mode mode;
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 1b2f18eab3..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());
}
@@ -142,8 +140,10 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return settings.value("fUseUPnP", GetBoolArg("-upnp", true));
case MinimizeOnClose:
return QVariant(fMinimizeOnClose);
- case ProxyUse:
- return settings.value("fUseProxy", false);
+ case ProxyUse: {
+ proxyType proxy;
+ return QVariant(GetProxy(NET_IPV4, proxy));
+ }
case ProxyIP: {
proxyType proxy;
if (GetProxy(NET_IPV4, proxy))
@@ -158,16 +158,19 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
else
return QVariant(9050);
}
- case ProxySocksVersion:
- return settings.value("nSocksVersion", 5);
+ case ProxySocksVersion: {
+ proxyType proxy;
+ if (GetProxy(NET_IPV4, proxy))
+ return QVariant(proxy.second);
+ else
+ return QVariant(5);
+ }
case Fee:
return QVariant(nTransactionFee);
case DisplayUnit:
return QVariant(nDisplayUnit);
case DisplayAddresses:
return QVariant(bDisplayAddresses);
- case DetachDatabases:
- return QVariant(bitdb.GetDetach());
case Language:
return settings.value("language", "");
default:
@@ -203,7 +206,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
case ProxyUse:
settings.setValue("fUseProxy", value.toBool());
- ApplyProxySettings();
+ successful = ApplyProxySettings();
break;
case ProxyIP: {
proxyType proxy;
@@ -249,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/overviewpage.cpp b/src/qt/overviewpage.cpp
index 07be9c520a..8f1ff5325e 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -1,6 +1,7 @@
#include "overviewpage.h"
#include "ui_overviewpage.h"
+#include "clientmodel.h"
#include "walletmodel.h"
#include "bitcoinunits.h"
#include "optionsmodel.h"
@@ -92,6 +93,8 @@ public:
OverviewPage::OverviewPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
+ clientModel(0),
+ walletModel(0),
currentBalance(-1),
currentUnconfirmedBalance(-1),
currentImmatureBalance(-1),
@@ -129,7 +132,7 @@ OverviewPage::~OverviewPage()
void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance)
{
- int unit = model->getOptionsModel()->getDisplayUnit();
+ int unit = walletModel->getOptionsModel()->getDisplayUnit();
currentBalance = balance;
currentUnconfirmedBalance = unconfirmedBalance;
currentImmatureBalance = immatureBalance;
@@ -149,9 +152,20 @@ void OverviewPage::setNumTransactions(int count)
ui->labelNumTransactions->setText(QLocale::system().toString(count));
}
-void OverviewPage::setModel(WalletModel *model)
+void OverviewPage::setClientModel(ClientModel *model)
{
- this->model = model;
+ this->clientModel = model;
+ if(model)
+ {
+ // Show warning if this is a prerelease version
+ connect(model, SIGNAL(alertsChanged(QString)), this, SLOT(updateAlerts(QString)));
+ updateAlerts(model->getStatusBarWarnings());
+ }
+}
+
+void OverviewPage::setWalletModel(WalletModel *model)
+{
+ this->walletModel = model;
if(model && model->getOptionsModel())
{
// Set up transaction list
@@ -181,18 +195,24 @@ void OverviewPage::setModel(WalletModel *model)
void OverviewPage::updateDisplayUnit()
{
- if(model && model->getOptionsModel())
+ if(walletModel && walletModel->getOptionsModel())
{
if(currentBalance != -1)
setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
// Update txdelegate->unit with the current unit
- txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
+ txdelegate->unit = walletModel->getOptionsModel()->getDisplayUnit();
ui->listTransactions->update();
}
}
+void OverviewPage::updateAlerts(const QString &warnings)
+{
+ this->ui->labelAlerts->setVisible(!warnings.isEmpty());
+ this->ui->labelAlerts->setText(warnings);
+}
+
void OverviewPage::showOutOfSyncWarning(bool fShow)
{
ui->labelWalletStatus->setVisible(fShow);
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 00048cc8f8..bb32a0c33f 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -10,6 +10,7 @@ QT_END_NAMESPACE
namespace Ui {
class OverviewPage;
}
+class ClientModel;
class WalletModel;
class TxViewDelegate;
class TransactionFilterProxy;
@@ -23,7 +24,8 @@ public:
explicit OverviewPage(QWidget *parent = 0);
~OverviewPage();
- void setModel(WalletModel *model);
+ void setClientModel(ClientModel *clientModel);
+ void setWalletModel(WalletModel *walletModel);
void showOutOfSyncWarning(bool fShow);
public slots:
@@ -35,7 +37,8 @@ signals:
private:
Ui::OverviewPage *ui;
- WalletModel *model;
+ ClientModel *clientModel;
+ WalletModel *walletModel;
qint64 currentBalance;
qint64 currentUnconfirmedBalance;
qint64 currentImmatureBalance;
@@ -46,6 +49,7 @@ private:
private slots:
void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
+ void updateAlerts(const QString &warnings);
};
#endif // OVERVIEWPAGE_H
diff --git a/src/qt/qtipcserver.cpp b/src/qt/qtipcserver.cpp
index 74f44fac57..b26c37581c 100644
--- a/src/qt/qtipcserver.cpp
+++ b/src/qt/qtipcserver.cpp
@@ -26,7 +26,7 @@ using namespace boost;
using namespace boost::interprocess;
using namespace boost::posix_time;
-#ifdef MAC_OSX
+#if defined MAC_OSX || defined __FreeBSD__
// URI handling not implemented on OSX yet
void ipcScanRelay(int argc, char *argv[]) { }
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 2b8a0c049b..3dc32d0e47 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -15,12 +15,11 @@
#include <openssl/crypto.h>
+// TODO: add a scrollback limit, as there is currently none
// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel
-const int CONSOLE_SCROLLBACK = 50;
const int CONSOLE_HISTORY = 50;
-
const QSize ICON_SIZE(24, 24);
const struct {
@@ -289,6 +288,8 @@ static QString categoryClass(int category)
void RPCConsole::clear()
{
ui->messagesWidget->clear();
+ history.clear();
+ historyPtr = 0;
ui->lineEdit->clear();
ui->lineEdit->setFocus();
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/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3568616cd3..9d5a2c04ff 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -189,7 +189,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
}
return TransactionCreationFailed;
}
- if(!uiInterface.ThreadSafeAskFee(nFeeRequired, tr("Sending...").toStdString()))
+ if(!uiInterface.ThreadSafeAskFee(nFeeRequired))
{
return Aborted;
}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 62558a49df..fd5c8c4d4f 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -147,8 +147,8 @@ signals:
// this means that the unlocking failed or was cancelled.
void requireUnlock();
- // Asynchronous error notification
- void error(const QString &title, const QString &message, bool modal);
+ // Asynchronous message notification
+ void message(const QString &title, const QString &message, unsigned int style);
public slots:
/* Wallet status might have changed */
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 3fde463cd3..5554f039a7 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -154,7 +154,7 @@ Value getblock(const Array& params, bool fHelp)
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
- block.ReadFromDisk(pblockindex, true);
+ block.ReadFromDisk(pblockindex);
return blockToJSON(block, pblockindex);
}
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 0270b5f102..0591f35392 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -198,7 +198,7 @@ Value getwork(const Array& params, bool fHelp)
Value getblocktemplate(const Array& params, bool fHelp)
{
- if (fHelp || params.size() != 1)
+ if (fHelp || params.size() > 1)
throw runtime_error(
"getblocktemplate [params]\n"
"Returns data needed to construct a block to work on:\n"
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 72a89c08c1..9531b12678 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -18,6 +18,39 @@ using namespace boost;
using namespace boost::assign;
using namespace json_spirit;
+//
+// Utilities: convert hex-encoded Values
+// (throws error if not hex).
+//
+uint256 ParseHashV(const Value& v, string strName)
+{
+ string strHex;
+ if (v.type() == str_type)
+ strHex = v.get_str();
+ if (!IsHex(strHex)) // Note: IsHex("") is false
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ uint256 result;
+ result.SetHex(strHex);
+ return result;
+}
+uint256 ParseHashO(const Object& o, string strKey)
+{
+ return ParseHashV(find_value(o, strKey), strKey);
+}
+vector<unsigned char> ParseHexV(const Value& v, string strName)
+{
+ string strHex;
+ if (v.type() == str_type)
+ strHex = v.get_str();
+ if (!IsHex(strHex))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ return ParseHex(strHex);
+}
+vector<unsigned char> ParseHexO(const Object& o, string strKey)
+{
+ return ParseHexV(find_value(o, strKey), strKey);
+}
+
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
{
txnouttype type;
@@ -109,8 +142,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
"If verbose is non-zero, returns an Object\n"
"with information about <txid>.");
- uint256 hash;
- hash.SetHex(params[0].get_str());
+ uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false;
if (params.size() > 1)
@@ -178,10 +210,10 @@ Value listunspent(const Array& params, bool fHelp)
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
- if(setAddress.size())
+ if (setAddress.size())
{
CTxDestination address;
- if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
+ if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
continue;
if (!setAddress.count(address))
@@ -194,6 +226,17 @@ Value listunspent(const Array& params, bool fHelp)
entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
entry.push_back(Pair("vout", out.i));
entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
+ if (pk.IsPayToScriptHash())
+ {
+ CTxDestination address;
+ if (ExtractDestination(pk, address))
+ {
+ const CScriptID& hash = boost::get<const CScriptID&>(address);
+ CScript redeemScript;
+ if (pwalletMain->GetCScript(hash, redeemScript))
+ entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
+ }
+ }
entry.push_back(Pair("amount",ValueFromAmount(nValue)));
entry.push_back(Pair("confirmations",out.nDepth));
results.push_back(entry);
@@ -221,16 +264,11 @@ Value createrawtransaction(const Array& params, bool fHelp)
CTransaction rawTx;
- BOOST_FOREACH(Value& input, inputs)
+ BOOST_FOREACH(const Value& input, inputs)
{
const Object& o = input.get_obj();
- const Value& txid_v = find_value(o, "txid");
- if (txid_v.type() != str_type)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
- string txid = txid_v.get_str();
- if (!IsHex(txid))
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
+ uint256 txid = ParseHashO(o, "txid");
const Value& vout_v = find_value(o, "vout");
if (vout_v.type() != int_type)
@@ -239,7 +277,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
if (nOutput < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
- CTxIn in(COutPoint(uint256(txid), nOutput));
+ CTxIn in(COutPoint(txid, nOutput));
rawTx.vin.push_back(in);
}
@@ -274,9 +312,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
"decoderawtransaction <hex string>\n"
"Return a JSON object representing the serialized, hex-encoded transaction.");
- RPCTypeCheck(params, list_of(str_type));
-
- vector<unsigned char> txData(ParseHex(params[0].get_str()));
+ vector<unsigned char> txData(ParseHexV(params[0], "argument"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
try {
@@ -296,10 +332,10 @@ Value signrawtransaction(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 4)
throw runtime_error(
- "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
+ "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
"Sign inputs for raw transaction (serialized, hex-encoded).\n"
"Second optional argument (may be null) is an array of previous transaction outputs that\n"
- "this transaction depends on but may not yet be in the blockchain.\n"
+ "this transaction depends on but may not yet be in the block chain.\n"
"Third optional argument (may be null) is an array of base58-encoded private\n"
"keys that, if given, will be the only keys used to sign the transaction.\n"
"Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
@@ -311,7 +347,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
- vector<unsigned char> txData(ParseHex(params[0].get_str()));
+ vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
vector<CTransaction> txVariants;
while (!ssData.empty())
@@ -352,6 +388,28 @@ Value signrawtransaction(const Array& params, bool fHelp)
view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
}
+ bool fGivenKeys = false;
+ CBasicKeyStore tempKeystore;
+ if (params.size() > 2 && params[2].type() != null_type)
+ {
+ fGivenKeys = true;
+ Array keys = params[2].get_array();
+ BOOST_FOREACH(Value k, keys)
+ {
+ CBitcoinSecret vchSecret;
+ bool fGood = vchSecret.SetString(k.get_str());
+ if (!fGood)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
+ CKey key;
+ bool fCompressed;
+ CSecret secret = vchSecret.GetSecret(fCompressed);
+ key.SetSecret(secret, fCompressed);
+ tempKeystore.AddKey(key);
+ }
+ }
+ else
+ EnsureWalletIsUnlocked();
+
// Add previous txouts given in the RPC call:
if (params.size() > 1 && params[1].type() != null_type)
{
@@ -363,22 +421,15 @@ Value signrawtransaction(const Array& params, bool fHelp)
Object prevOut = p.get_obj();
- RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
+ RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
- string txidHex = find_value(prevOut, "txid").get_str();
- if (!IsHex(txidHex))
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
- uint256 txid;
- txid.SetHex(txidHex);
+ uint256 txid = ParseHashO(prevOut, "txid");
int nOut = find_value(prevOut, "vout").get_int();
if (nOut < 0)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
- string pkHex = find_value(prevOut, "scriptPubKey").get_str();
- if (!IsHex(pkHex))
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
- vector<unsigned char> pkData(ParseHex(pkHex));
+ vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
CCoins coins;
@@ -391,33 +442,23 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
// what todo if txid is known, but the actual output isn't?
}
+ if ((unsigned int)nOut >= coins.vout.size())
+ coins.vout.resize(nOut+1);
coins.vout[nOut].scriptPubKey = scriptPubKey;
coins.vout[nOut].nValue = 0; // we don't know the actual output value
view.SetCoins(txid, coins);
- }
- }
- bool fGivenKeys = false;
- CBasicKeyStore tempKeystore;
- if (params.size() > 2 && params[2].type() != null_type)
- {
- fGivenKeys = true;
- Array keys = params[2].get_array();
- BOOST_FOREACH(Value k, keys)
- {
- CBitcoinSecret vchSecret;
- bool fGood = vchSecret.SetString(k.get_str());
- if (!fGood)
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
- CKey key;
- bool fCompressed;
- CSecret secret = vchSecret.GetSecret(fCompressed);
- key.SetSecret(secret, fCompressed);
- tempKeystore.AddKey(key);
+ // if redeemScript given and not using the local wallet (private keys
+ // given), add redeemScript to the tempKeystore so it can be signed:
+ Value v = find_value(prevOut, "redeemScript");
+ if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && !(v == Value::null))
+ {
+ vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
+ CScript redeemScript(rsData.begin(), rsData.end());
+ tempKeystore.AddCScript(redeemScript);
+ }
}
}
- else
- EnsureWalletIsUnlocked();
const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
@@ -464,7 +505,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
{
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
- if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, true, 0))
+ if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
fComplete = false;
}
@@ -484,10 +525,8 @@ Value sendrawtransaction(const Array& params, bool fHelp)
"sendrawtransaction <hex string>\n"
"Submits raw transaction (serialized, hex-encoded) to local node and network.");
- RPCTypeCheck(params, list_of(str_type));
-
// parse hex string from parameter
- vector<unsigned char> txData(ParseHex(params[0].get_str()));
+ vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 6f8728e979..90a68f560a 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -3,14 +3,18 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <boost/assign/list_of.hpp>
+
#include "wallet.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
#include "init.h"
#include "base58.h"
-using namespace json_spirit;
using namespace std;
+using namespace boost;
+using namespace boost::assign;
+using namespace json_spirit;
int64 nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
@@ -573,7 +577,7 @@ Value movecmd(const Array& params, bool fHelp)
// Debit
CAccountingEntry debit;
- debit.nOrderPos = pwalletMain->IncOrderPosNext();
+ debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
debit.strAccount = strFrom;
debit.nCreditDebit = -nAmount;
debit.nTime = nNow;
@@ -583,7 +587,7 @@ Value movecmd(const Array& params, bool fHelp)
// Credit
CAccountingEntry credit;
- credit.nOrderPos = pwalletMain->IncOrderPosNext();
+ credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
credit.strAccount = strTo;
credit.nCreditDebit = nAmount;
credit.nTime = nNow;
@@ -702,22 +706,13 @@ Value sendmany(const Array& params, bool fHelp)
return wtx.GetHash().GetHex();
}
-Value addmultisigaddress(const Array& params, bool fHelp)
+//
+// Used by addmultisigaddress / createmultisig:
+//
+static CScript _createmultisig(const Array& params)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
- {
- string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
- "Add a nrequired-to-sign multisignature address to the wallet\"\n"
- "each key is a Bitcoin address or hex-encoded public key\n"
- "If [account] is specified, assign address to [account].";
- throw runtime_error(msg);
- }
-
int nRequired = params[0].get_int();
const Array& keys = params[1].get_array();
- string strAccount;
- if (params.size() > 2)
- strAccount = AccountFromValue(params[2]);
// Gather public keys
if (nRequired < 1)
@@ -760,10 +755,28 @@ Value addmultisigaddress(const Array& params, bool fHelp)
throw runtime_error(" Invalid public key: "+ks);
}
}
+ CScript result;
+ result.SetMultisig(nRequired, pubkeys);
+ return result;
+}
+
+Value addmultisigaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 3)
+ {
+ string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
+ "Add a nrequired-to-sign multisignature address to the wallet\"\n"
+ "each key is a Bitcoin address or hex-encoded public key\n"
+ "If [account] is specified, assign address to [account].";
+ throw runtime_error(msg);
+ }
+
+ string strAccount;
+ if (params.size() > 2)
+ strAccount = AccountFromValue(params[2]);
// Construct using pay-to-script-hash:
- CScript inner;
- inner.SetMultisig(nRequired, pubkeys);
+ CScript inner = _createmultisig(params);
CScriptID innerID = inner.GetID();
pwalletMain->AddCScript(inner);
@@ -771,6 +784,30 @@ Value addmultisigaddress(const Array& params, bool fHelp)
return CBitcoinAddress(innerID).ToString();
}
+Value createmultisig(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 2)
+ {
+ string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
+ "Creates a multi-signature address and returns a json object\n"
+ "with keys:\n"
+ "address : bitcoin address\n"
+ "redeemScript : hex-encoded redemption script";
+ throw runtime_error(msg);
+ }
+
+ // Construct using pay-to-script-hash:
+ CScript inner = _createmultisig(params);
+ CScriptID innerID = inner.GetID();
+ CBitcoinAddress address(innerID);
+
+ Object result;
+ result.push_back(Pair("address", address.ToString()));
+ result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
+
+ return result;
+}
+
struct tallyitem
{
@@ -1195,7 +1232,8 @@ 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(*pwalletMain, strDest);
+ if (!BackupWallet(*pwalletMain, strDest))
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return Value::null;
}
@@ -1396,7 +1434,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>
@@ -1463,3 +1501,74 @@ Value validateaddress(const Array& params, bool fHelp)
return ret;
}
+Value lockunspent(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "lockunspent unlock? [array-of-Objects]\n"
+ "Updates list of temporarily unspendable outputs.");
+
+ if (params.size() == 1)
+ RPCTypeCheck(params, list_of(bool_type));
+ else
+ RPCTypeCheck(params, list_of(bool_type)(array_type));
+
+ bool fUnlock = params[0].get_bool();
+
+ if (params.size() == 1) {
+ if (fUnlock)
+ pwalletMain->UnlockAllCoins();
+ return true;
+ }
+
+ Array outputs = params[1].get_array();
+ BOOST_FOREACH(Value& output, outputs)
+ {
+ if (output.type() != obj_type)
+ throw JSONRPCError(-8, "Invalid parameter, expected object");
+ const Object& o = output.get_obj();
+
+ RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type));
+
+ string txid = find_value(o, "txid").get_str();
+ if (!IsHex(txid))
+ throw JSONRPCError(-8, "Invalid parameter, expected hex txid");
+
+ int nOutput = find_value(o, "vout").get_int();
+ if (nOutput < 0)
+ throw JSONRPCError(-8, "Invalid parameter, vout must be positive");
+
+ COutPoint outpt(uint256(txid), nOutput);
+
+ if (fUnlock)
+ pwalletMain->UnlockCoin(outpt);
+ else
+ pwalletMain->LockCoin(outpt);
+ }
+
+ return true;
+}
+
+Value listlockunspent(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 0)
+ throw runtime_error(
+ "listlockunspent\n"
+ "Returns list of temporarily unspendable outputs.");
+
+ vector<COutPoint> vOutpts;
+ pwalletMain->ListLockedCoins(vOutpts);
+
+ Array ret;
+
+ BOOST_FOREACH(COutPoint &outpt, vOutpts) {
+ Object o;
+
+ o.push_back(Pair("txid", outpt.hash.GetHex()));
+ o.push_back(Pair("vout", (int)outpt.n));
+ ret.push_back(o);
+ }
+
+ return ret;
+}
+
diff --git a/src/script.cpp b/src/script.cpp
index 36d208c247..f65508aacc 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -314,7 +314,7 @@ bool IsCanonicalSignature(const valtype &vchSig) {
return true;
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, bool fStrictEncodings, int nHashType)
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
{
CAutoBN_CTX pctx;
CScript::const_iterator pc = script.begin();
@@ -327,7 +327,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
if (script.size() > 10000)
return false;
int nOpCount = 0;
-
+ bool fStrictEncodings = flags & SCRIPT_VERIFY_STRICTENC;
try
{
@@ -1637,14 +1637,14 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType)
+ unsigned int flags, int nHashType)
{
vector<vector<unsigned char> > stack, stackCopy;
- if (!EvalScript(stack, scriptSig, txTo, nIn, fStrictEncodings, nHashType))
+ if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType))
return false;
- if (fValidatePayToScriptHash)
+ if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack;
- if (!EvalScript(stack, scriptPubKey, txTo, nIn, fStrictEncodings, nHashType))
+ if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags, nHashType))
return false;
if (stack.empty())
return false;
@@ -1653,16 +1653,21 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
return false;
// Additional validation for spend-to-script-hash transactions:
- if (fValidatePayToScriptHash && scriptPubKey.IsPayToScriptHash())
+ if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
{
if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only
return false; // or validation fails
+ // stackCopy cannot be empty here, because if it was the
+ // P2SH HASH <> EQUAL scriptPubKey would be evaluated with
+ // an empty stack and the EvalScript above would return false.
+ assert(!stackCopy.empty());
+
const valtype& pubKeySerialized = stackCopy.back();
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stackCopy);
- if (!EvalScript(stackCopy, pubKey2, txTo, nIn, fStrictEncodings, nHashType))
+ if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags, nHashType))
return false;
if (stackCopy.empty())
return false;
@@ -1705,7 +1710,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa
}
// Test solution
- return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, true, 0);
+ return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0);
}
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType)
@@ -1718,7 +1723,7 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
}
-bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType)
+bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType)
{
assert(nIn < txTo.vin.size());
const CTxIn& txin = txTo.vin[nIn];
@@ -1726,7 +1731,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return false;
const CTxOut& txout = txFrom.vout[txin.prevout.n];
- return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, fStrictEncodings, nHashType);
+ return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, flags, nHashType);
}
static CScript PushAll(const vector<valtype>& values)
@@ -1844,9 +1849,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign
Solver(scriptPubKey, txType, vSolutions);
vector<valtype> stack1;
- EvalScript(stack1, scriptSig1, CTransaction(), 0, true, 0);
+ EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
vector<valtype> stack2;
- EvalScript(stack2, scriptSig2, CTransaction(), 0, true, 0);
+ EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0);
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
}
diff --git a/src/script.h b/src/script.h
index f9df587ca3..7b0643f70a 100644
--- a/src/script.h
+++ b/src/script.h
@@ -26,6 +26,13 @@ enum
SIGHASH_ANYONECANPAY = 0x80,
};
+/** Script verification flags */
+enum
+{
+ SCRIPT_VERIFY_NONE = 0,
+ SCRIPT_VERIFY_P2SH = (1U << 0),
+ SCRIPT_VERIFY_STRICTENC = (1U << 1),
+};
enum txnouttype
{
@@ -656,7 +663,7 @@ public:
bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey);
bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig);
-bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, bool fStrictEncodings, int nHashType);
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
bool IsStandard(const CScript& scriptPubKey);
@@ -667,8 +674,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType);
-bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType);
+ unsigned int flags, int nHashType);
+bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
// Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
// combine them intelligently and return the result.
diff --git a/src/serialize.h b/src/serialize.h
index 549e46cbc3..f2626281c1 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -50,10 +50,6 @@ enum
SER_NETWORK = (1 << 0),
SER_DISK = (1 << 1),
SER_GETHASH = (1 << 2),
-
- // modifiers
- SER_SKIPSIG = (1 << 16),
- SER_BLOCKHEADERONLY = (1 << 17),
};
#define IMPLEMENT_SERIALIZE(statements) \
@@ -1225,4 +1221,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/sync.h b/src/sync.h
index e80efbe001..9dfc6697c6 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -37,46 +37,31 @@ class CMutexLock
{
private:
boost::unique_lock<Mutex> lock;
-public:
void Enter(const char* pszName, const char* pszFile, int nLine)
{
- if (!lock.owns_lock())
- {
- EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
+ EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
#ifdef DEBUG_LOCKCONTENTION
- if (!lock.try_lock())
- {
- PrintLockContention(pszName, pszFile, nLine);
+ if (!lock.try_lock())
+ {
+ PrintLockContention(pszName, pszFile, nLine);
#endif
- lock.lock();
+ lock.lock();
#ifdef DEBUG_LOCKCONTENTION
- }
-#endif
- }
- }
-
- void Leave()
- {
- if (lock.owns_lock())
- {
- lock.unlock();
- LeaveCritical();
}
+#endif
}
bool TryEnter(const char* pszName, const char* pszFile, int nLine)
{
+ EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
+ lock.try_lock();
if (!lock.owns_lock())
- {
- EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
- lock.try_lock();
- if (!lock.owns_lock())
- LeaveCritical();
- }
+ LeaveCritical();
return lock.owns_lock();
}
+public:
CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
{
if (fTry)
@@ -95,11 +80,6 @@ public:
{
return lock.owns_lock();
}
-
- boost::unique_lock<Mutex> &GetLock()
- {
- return lock;
- }
};
typedef CMutexLock<CCriticalSection> CCriticalBlock;
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 8235b0bda7..b1e98f65ed 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -46,7 +46,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
dummyNode2.Misbehaving(50);
BOOST_CHECK(CNode::IsBanned(addr2));
-}
+}
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
@@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits)
{
using namespace boost::assign; // for 'map_list_of()'
- // Timestamps,nBits from the bitcoin blockchain.
+ // Timestamps,nBits from the bitcoin block chain.
// These are the block-chain checkpoint blocks
typedef std::map<int64, unsigned int> BlockData;
BlockData chainData =
@@ -129,7 +129,6 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits)
// ... but OK if enough time passed for difficulty to adjust downward:
BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
-
}
CTransaction RandomOrphan()
@@ -231,6 +230,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
key.MakeNewKey(true);
CBasicKeyStore keystore;
keystore.AddKey(key);
+ unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
// 100 orphan transactions:
static const int NPREV=100;
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
mst1 = boost::posix_time::microsec_clock::local_time();
for (unsigned int i = 0; i < 5; i++)
for (unsigned int j = 0; j < tx.vin.size(); j++)
- BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, true, true, SIGHASH_ALL));
+ BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
mst2 = boost::posix_time::microsec_clock::local_time();
msdiff = mst2 - mst1;
long nManyValidate = msdiff.total_milliseconds();
@@ -289,13 +289,13 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
// Empty a signature, validation should fail:
CScript save = tx.vin[0].scriptSig;
tx.vin[0].scriptSig = CScript();
- BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, true, true, SIGHASH_ALL));
+ BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
tx.vin[0].scriptSig = save;
// Swap signatures, validation should fail:
std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
- BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, true, true, SIGHASH_ALL));
- BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, true, true, SIGHASH_ALL));
+ BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL));
+ BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, SIGHASH_ALL));
std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig);
// Exercise -maxsigcachesize code:
@@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig)
BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0));
BOOST_CHECK(tx.vin[0].scriptSig != oldSig);
for (unsigned int j = 0; j < tx.vin.size(); j++)
- BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, true, true, SIGHASH_ALL));
+ BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL));
mapArgs.erase("-maxsigcachesize");
LimitOrphanTxSize(0);
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index aa6feb7201..7297bb9a75 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -20,8 +20,6 @@ using namespace boost::assign;
typedef vector<unsigned char> valtype;
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType);
BOOST_AUTO_TEST_SUITE(multisig_tests)
@@ -44,6 +42,8 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
BOOST_AUTO_TEST_CASE(multisig_verify)
{
+ unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
+
CKey key[4];
for (int i = 0; i < 4; i++)
key[i].MakeNewKey(true);
@@ -80,19 +80,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.clear();
keys += key[0],key[1]; // magic operator+= from boost.assign
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, true, 0));
+ BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags, 0));
for (int i = 0; i < 4; i++)
{
keys.clear();
keys += key[i];
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, true, 0), strprintf("a&b 1: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 1: %d", i));
keys.clear();
keys += key[1],key[i];
s = sign_multisig(a_and_b, keys, txTo[0], 0);
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, true, 0), strprintf("a&b 2: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 2: %d", i));
}
// Test a OR b:
@@ -102,16 +102,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys += key[i];
s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1)
- BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i));
else
- BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0), strprintf("a|b: %d", i));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i));
}
s.clear();
s << OP_0 << OP_0;
- BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0));
s.clear();
s << OP_0 << OP_1;
- BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0));
for (int i = 0; i < 4; i++)
@@ -121,9 +121,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys += key[i],key[j];
s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3)
- BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, true, 0), strprintf("escrow 1: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 1: %d %d", i, j));
else
- BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, true, 0), strprintf("escrow 2: %d %d", i, j));
+ BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 2: %d %d", i, j));
}
}
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index eb820ade6d..f8fe443b87 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -1,5 +1,6 @@
-#include <boost/test/unit_test.hpp>
+#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
#include "base58.h"
#include "util.h"
@@ -22,14 +23,7 @@ createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
return result;
}
-// This can be removed this when addmultisigaddress is enabled on main net:
-struct TestNetFixture
-{
- TestNetFixture() { fTestNet = true; }
- ~TestNetFixture() { fTestNet = false; }
-};
-
-BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
+BOOST_AUTO_TEST_CASE(rpc_addmultisig)
{
rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
@@ -66,4 +60,91 @@ BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
}
+static Value CallRPC(string args)
+{
+ vector<string> vArgs;
+ boost::split(vArgs, args, boost::is_any_of(" \t"));
+ string strMethod = vArgs[0];
+ vArgs.erase(vArgs.begin());
+ Array params = RPCConvertValues(strMethod, vArgs);
+
+ rpcfn_type method = tableRPC[strMethod]->actor;
+ try {
+ Value result = (*method)(params, false);
+ return result;
+ }
+ catch (Object& objError)
+ {
+ throw runtime_error(find_value(objError, "message").get_str());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(rpc_rawparams)
+{
+ // Test raw transaction API argument handling
+ Value r;
+
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
+ BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
+ BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []"));
+ BOOST_CHECK_THROW(r=CallRPC("listunspent 0 1 [] extra"), runtime_error);
+ BOOST_CHECK(r.get_array().empty());
+
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}"));
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
+ string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
+ BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);
+
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error);
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx));
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
+ BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
+ BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error);
+
+ // Only check failure cases for sendrawtransaction, there's no network to send to...
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_rawsign)
+{
+ Value r;
+ // input is a 1-of-2 multisig (so is output):
+ string prevout =
+ "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
+ "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\","
+ "\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]";
+ r = CallRPC(string("createrawtransaction ")+prevout+" "+
+ "{\"3HqAe9LtNBjnsfM4CyYaWTnvCaUYT7v4oZ\":11}");
+ string notsigned = r.get_str();
+ string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
+ string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
+ r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]");
+ BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
+ r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]");
+ BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 35069a3fdd..b5107193fd 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -13,8 +13,6 @@ using namespace std;
// Test routines internal to script.cpp:
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType);
// Helpers:
static std::vector<unsigned char>
@@ -40,7 +38,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1;
- return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, true, 0);
+ return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0);
}
@@ -105,7 +103,7 @@ BOOST_AUTO_TEST_CASE(sign)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- bool sigOK = VerifySignature(CCoins(txFrom, 0), txTo[i], 0, true, true, 0);
+ bool sigOK = VerifySignature(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0);
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index f8e4fa8a49..5d5a1525f7 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -20,8 +20,8 @@ using namespace json_spirit;
using namespace boost::algorithm;
extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
-extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
- bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType);
+
+static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
CScript
ParseScript(string s)
@@ -79,7 +79,7 @@ ParseScript(string s)
{
BOOST_ERROR("Parse error: " << s);
return CScript();
- }
+ }
}
return result;
@@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(script_valid)
CScript scriptPubKey = ParseScript(scriptPubKeyString);
CTransaction tx;
- BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, true, SIGHASH_NONE), strTest);
+ BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, flags, SIGHASH_NONE), strTest);
}
}
@@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(script_invalid)
CScript scriptPubKey = ParseScript(scriptPubKeyString);
CTransaction tx;
- BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, true, SIGHASH_NONE), strTest);
+ BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, flags, SIGHASH_NONE), strTest);
}
}
@@ -206,7 +206,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
// NOTE: CHECKMULTISIG has an unfortunate bug; it requires
// one extra item on the stack, before the signatures.
// Putting OP_0 on the stack is the workaround;
- // fixing the bug would mean splitting the blockchain (old
+ // fixing the bug would mean splitting the block chain (old
// clients would not accept new CHECKMULTISIG transactions,
// and vice-versa)
//
@@ -250,15 +250,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
txTo12.vout[0].nValue = 1;
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, true, 0));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0));
txTo12.vout[0].nValue = 2;
- BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, true, 0));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, flags, 0));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
- BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, flags, 0));
}
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
@@ -286,46 +286,46 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, flags, 0));
keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
- BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, true, 0));
+ BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, flags, 0));
}
BOOST_AUTO_TEST_CASE(script_combineSigs)
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index c1f47f786b..b98816d53d 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -1,10 +1,12 @@
#define BOOST_TEST_MODULE Bitcoin Test Suite
#include <boost/test/unit_test.hpp>
+#include <boost/filesystem.hpp>
#include "db.h"
#include "txdb.h"
#include "main.h"
#include "wallet.h"
+#include "util.h"
CWallet* pwalletMain;
CClientUIInterface uiInterface;
@@ -14,15 +16,19 @@ extern void noui_connect();
struct TestingSetup {
CCoinsViewDB *pcoinsdbview;
+ boost::filesystem::path pathTemp;
TestingSetup() {
fPrintToDebugger = true; // don't want to write to debug.log file
noui_connect();
bitdb.MakeMock();
- pblocktree = new CBlockTreeDB(true);
- pcoinsdbview = new CCoinsViewDB(true);
+ pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
+ boost::filesystem::create_directories(pathTemp);
+ mapArgs["-datadir"] = pathTemp.string();
+ 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);
@@ -36,6 +42,7 @@ struct TestingSetup {
delete pcoinsdbview;
delete pblocktree;
bitdb.Flush(true);
+ boost::filesystem::remove_all(pathTemp);
}
};
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 4385b9ba37..23837c6c15 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
break;
}
- BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), false, 0), strTest);
+ BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0), strTest);
}
}
}
@@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
break;
}
- fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), true, 0);
+ fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 67d15cb58f..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) {
@@ -58,12 +58,13 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockI
CLevelDBBatch batch;
for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
BatchWriteCoins(batch, it->first, it->second);
- BatchWriteHashBestChain(batch, pindex->GetBlockHash());
+ if (pindex)
+ BatchWriteHashBestChain(batch, pindex->GetBlockHash());
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)
@@ -93,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/ui_interface.h b/src/ui_interface.h
index 0f7fdef264..703e15f095 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -29,41 +29,49 @@ public:
/** Flags for CClientUIInterface::ThreadSafeMessageBox */
enum MessageBoxFlags
{
- YES = 0x00000002,
- OK = 0x00000004,
- NO = 0x00000008,
- YES_NO = (YES|NO),
- CANCEL = 0x00000010,
- APPLY = 0x00000020,
- CLOSE = 0x00000040,
- OK_DEFAULT = 0x00000000,
- YES_DEFAULT = 0x00000000,
- NO_DEFAULT = 0x00000080,
- CANCEL_DEFAULT = 0x80000000,
- ICON_EXCLAMATION = 0x00000100,
- ICON_HAND = 0x00000200,
- ICON_WARNING = ICON_EXCLAMATION,
- ICON_ERROR = ICON_HAND,
- ICON_QUESTION = 0x00000400,
- ICON_INFORMATION = 0x00000800,
- ICON_STOP = ICON_HAND,
- ICON_ASTERISK = ICON_INFORMATION,
- ICON_MASK = (0x00000100|0x00000200|0x00000400|0x00000800),
- FORWARD = 0x00001000,
- BACKWARD = 0x00002000,
- RESET = 0x00004000,
- HELP = 0x00008000,
- MORE = 0x00010000,
- SETUP = 0x00020000,
- // Force blocking, modal message box dialog (not just OS notification)
- MODAL = 0x00040000
+ ICON_INFORMATION = 0,
+ ICON_WARNING = (1U << 0),
+ ICON_ERROR = (1U << 1),
+ /**
+ * Mask of all available icons in CClientUIInterface::MessageBoxFlags
+ * This needs to be updated, when icons are changed there!
+ */
+ ICON_MASK = (ICON_INFORMATION | ICON_WARNING | ICON_ERROR),
+
+ /** These values are taken from qmessagebox.h "enum StandardButton" to be directly usable */
+ BTN_OK = 0x00000400U, // QMessageBox::Ok
+ BTN_YES = 0x00004000U, // QMessageBox::Yes
+ BTN_NO = 0x00010000U, // QMessageBox::No
+ BTN_ABORT = 0x00040000U, // QMessageBox::Abort
+ BTN_RETRY = 0x00080000U, // QMessageBox::Retry
+ BTN_IGNORE = 0x00100000U, // QMessageBox::Ignore
+ BTN_CLOSE = 0x00200000U, // QMessageBox::Close
+ BTN_CANCEL = 0x00400000U, // QMessageBox::Cancel
+ BTN_DISCARD = 0x00800000U, // QMessageBox::Discard
+ BTN_HELP = 0x01000000U, // QMessageBox::Help
+ BTN_APPLY = 0x02000000U, // QMessageBox::Apply
+ BTN_RESET = 0x04000000U, // QMessageBox::Reset
+ /**
+ * Mask of all available buttons in CClientUIInterface::MessageBoxFlags
+ * This needs to be updated, when buttons are changed there!
+ */
+ BTN_MASK = (BTN_OK | BTN_YES | BTN_NO | BTN_ABORT | BTN_RETRY | BTN_IGNORE |
+ BTN_CLOSE | BTN_CANCEL | BTN_DISCARD | BTN_HELP | BTN_APPLY | BTN_RESET),
+
+ /** Force blocking, modal message box dialog (not just OS notification) */
+ MODAL = 0x10000000U,
+
+ /** Predefined combinations for certain default usage cases */
+ MSG_INFORMATION = ICON_INFORMATION,
+ MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL),
+ MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL)
};
/** Show message box. */
- boost::signals2::signal<void (const std::string& message, const std::string& caption, int style)> ThreadSafeMessageBox;
+ boost::signals2::signal<void (const std::string& message, const std::string& caption, unsigned int style)> ThreadSafeMessageBox;
/** Ask the user whether they want to pay a fee or not. */
- boost::signals2::signal<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee;
+ boost::signals2::signal<bool (int64 nFeeRequired), boost::signals2::last_value<bool> > ThreadSafeAskFee;
/** Handle a URL passed at the command line. */
boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI;
diff --git a/src/util.cpp b/src/util.cpp
index 9162886450..3cbc6b196b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -64,7 +64,7 @@ bool fDebug = false;
bool fDebugNet = false;
bool fPrintToConsole = false;
bool fPrintToDebugger = false;
-bool fRequestShutdown = false;
+volatile bool fRequestShutdown = false;
bool fShutdown = false;
bool fDaemon = false;
bool fServer = false;
@@ -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
@@ -1248,7 +1248,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime)
string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION);
+ uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
}
}
}
@@ -1310,6 +1310,28 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
}
#endif
+boost::filesystem::path GetTempPath() {
+#if BOOST_FILESYSTEM_VERSION == 3
+ return boost::filesystem::temp_directory_path();
+#else
+ // TODO: remove when we don't support filesystem v2 anymore
+ boost::filesystem::path path;
+#ifdef WIN32
+ char pszPath[MAX_PATH] = "";
+
+ if (GetTempPathA(MAX_PATH, pszPath))
+ path = boost::filesystem::path(pszPath);
+#else
+ path = boost::filesystem::path("/tmp");
+#endif
+ if (path.empty() || !boost::filesystem::is_directory(path)) {
+ printf("GetTempPath(): failed to find temp path\n");
+ return boost::filesystem::path("");
+ }
+ return path;
+#endif
+}
+
void runCommand(std::string strCommand)
{
int nErr = ::system(strCommand.c_str());
diff --git a/src/util.h b/src/util.h
index b798f60aa7..ab921e6f05 100644
--- a/src/util.h
+++ b/src/util.h
@@ -132,7 +132,7 @@ extern bool fDebug;
extern bool fDebugNet;
extern bool fPrintToConsole;
extern bool fPrintToDebugger;
-extern bool fRequestShutdown;
+extern volatile bool fRequestShutdown;
extern bool fShutdown;
extern bool fDaemon;
extern bool fServer;
@@ -207,6 +207,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map
#ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
+boost::filesystem::path GetTempPath();
void ShrinkDebugFile();
int GetRandInt(int nMax);
uint64 GetRand(uint64 nMax);
@@ -329,6 +330,12 @@ inline int64 GetTimeMillis()
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
}
+inline int64 GetTimeMicros()
+{
+ return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
+ boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
+}
+
inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime)
{
time_t n = nTime;
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 1498ff28b7..c07adff6c6 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -291,10 +291,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return true;
}
-int64 CWallet::IncOrderPosNext()
+int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{
- int64 nRet = nOrderPosNext;
- CWalletDB(strWalletFile).WriteOrderPosNext(++nOrderPosNext);
+ int64 nRet = nOrderPosNext++;
+ if (pwalletdb) {
+ pwalletdb->WriteOrderPosNext(nOrderPosNext);
+ } else {
+ CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext);
+ }
return nRet;
}
@@ -752,7 +756,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
while (pindex)
{
CBlock block;
- block.ReadFromDisk(pindex, true);
+ block.ReadFromDisk(pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
@@ -780,8 +784,8 @@ void CWallet::ReacceptWalletTransactions()
CCoins coins;
bool fUpdated = false;
- bool fNotFound = pcoinsTip->GetCoins(wtx.GetHash(), coins);
- if (!fNotFound || wtx.GetDepthInMainChain() > 0)
+ bool fFound = pcoinsTip->GetCoins(wtx.GetHash(), coins);
+ if (fFound || wtx.GetDepthInMainChain() > 0)
{
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
for (unsigned int i = 0; i < wtx.vout.size(); i++)
@@ -820,21 +824,17 @@ void CWallet::ReacceptWalletTransactions()
void CWalletTx::RelayWalletTransaction()
{
- CCoinsViewCache& coins = *pcoinsTip;
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
{
- if (!tx.IsCoinBase())
- {
- uint256 hash = tx.GetHash();
- if (!coins.HaveCoins(hash))
- RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
+ if (!tx.IsCoinBase()) {
+ if (tx.GetDepthInMainChain() == 0)
+ RelayMessage(CInv(MSG_TX, tx.GetHash()), (CTransaction)tx);
}
}
if (!IsCoinBase())
{
- uint256 hash = GetHash();
- if (!coins.HaveCoins(hash))
- {
+ if (GetDepthInMainChain() == 0) {
+ uint256 hash = GetHash();
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
}
@@ -930,9 +930,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;
@@ -958,9 +957,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
- for (unsigned int i = 0; i < pcoin->vout.size(); i++)
- if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0)
+ for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
+ if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) &&
+ !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0)
vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
+ }
}
}
}
@@ -1296,7 +1297,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;
}
@@ -1304,18 +1305,18 @@ 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;
}
- if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending...")))
+ if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired))
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
- return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+ return _("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 "";
}
@@ -1771,3 +1772,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
NotifyTransactionChanged(this, hashTx, CT_UPDATED);
}
}
+
+void CWallet::LockCoin(COutPoint& output)
+{
+ setLockedCoins.insert(output);
+}
+
+void CWallet::UnlockCoin(COutPoint& output)
+{
+ setLockedCoins.erase(output);
+}
+
+void CWallet::UnlockAllCoins()
+{
+ setLockedCoins.clear();
+}
+
+bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
+{
+ COutPoint outpt(hash, n);
+
+ return (setLockedCoins.count(outpt) > 0);
+}
+
+void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
+{
+ for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
+ it != setLockedCoins.end(); it++) {
+ COutPoint outpt = (*it);
+ vOutpts.push_back(outpt);
+ }
+}
+
diff --git a/src/wallet.h b/src/wallet.h
index 43b695c597..ecfdafe2eb 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -119,11 +119,18 @@ public:
CPubKey vchDefaultKey;
+ std::set<COutPoint> setLockedCoins;
+
// check whether we are allowed to upgrade (or already support) to the named feature
bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const;
bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
+ bool IsLockedCoin(uint256 hash, unsigned int n) const;
+ void LockCoin(COutPoint& output);
+ void UnlockCoin(COutPoint& output);
+ void UnlockAllCoins();
+ void ListLockedCoins(std::vector<COutPoint>& vOutpts);
// keystore implementation
// Generate a new key
@@ -149,7 +156,7 @@ public:
/** Increment the next transaction order id
@return next transaction order id
*/
- int64 IncOrderPosNext();
+ int64 IncOrderPosNext(CWalletDB *pwalletdb = NULL);
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef std::multimap<int64, TxPair > TxItems;
@@ -375,10 +382,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 +425,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 +574,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