aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/addrman.cpp1
-rw-r--r--src/bignum.h72
-rw-r--r--src/bitcoinrpc.cpp9
-rw-r--r--src/bitcoinrpc.h2
-rw-r--r--src/checkpoints.cpp10
-rw-r--r--src/hash.h116
-rw-r--r--src/init.cpp33
-rw-r--r--src/key.h2
-rwxr-xr-xsrc/leveldb/build_detect_platform10
-rw-r--r--src/main.cpp195
-rw-r--r--src/main.h98
-rw-r--r--src/makefile.linux-mingw2
-rw-r--r--src/makefile.mingw4
-rw-r--r--src/makefile.osx2
-rw-r--r--src/makefile.unix2
-rw-r--r--src/net.h23
-rw-r--r--src/netbase.cpp1
-rw-r--r--src/noui.cpp23
-rw-r--r--src/qt/bitcoin.cpp12
-rw-r--r--src/qt/bitcoingui.cpp147
-rw-r--r--src/qt/bitcoingui.h15
-rw-r--r--src/qt/clientmodel.cpp2
-rw-r--r--src/qt/clientmodel.h4
-rw-r--r--src/qt/notificator.h8
-rw-r--r--src/qt/optionsmodel.cpp4
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/qt/walletmodel.h4
-rw-r--r--src/rpcblockchain.cpp2
-rw-r--r--src/rpcdump.cpp18
-rw-r--r--src/rpcwallet.cpp80
-rw-r--r--src/serialize.h4
-rw-r--r--src/sync.h65
-rw-r--r--src/test/bignum_tests.cpp53
-rw-r--r--src/test/test_bitcoin.cpp7
-rw-r--r--src/test/util_tests.cpp8
-rw-r--r--src/threadsafety.h53
-rw-r--r--src/ui_interface.h68
-rw-r--r--src/util.cpp28
-rw-r--r--src/util.h115
-rw-r--r--src/wallet.cpp42
-rw-r--r--src/wallet.h7
-rw-r--r--src/walletdb.cpp2
42 files changed, 926 insertions, 429 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 4428cd169a..780edde90f 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "addrman.h"
+#include "hash.h"
using namespace std;
diff --git a/src/bignum.h b/src/bignum.h
index 96b1b2e6ae..1ee7a99934 100644
--- a/src/bignum.h
+++ b/src/bignum.h
@@ -131,7 +131,9 @@ public:
if (sn < (int64)0)
{
- // Since the minimum signed integer cannot be represented as positive so long as its type is signed, and it's not well-defined what happens if you make it unsigned before negating it, we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate
+ // Since the minimum signed integer cannot be represented as positive so long as its type is signed,
+ // and it's not well-defined what happens if you make it unsigned before negating it,
+ // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate
n = -(sn + 1);
++n;
fNegative = true;
@@ -262,28 +264,68 @@ public:
return vch;
}
+ // The "compact" format is a representation of a whole
+ // number N using an unsigned 32bit number similar to a
+ // floating point format.
+ // The most significant 8 bits are the unsigned exponent of base 256.
+ // This exponent can be thought of as "number of bytes of N".
+ // The lower 23 bits are the mantissa.
+ // Bit number 24 (0x800000) represents the sign of N.
+ // N = (-1^sign) * mantissa * 256^(exponent-3)
+ //
+ // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn().
+ // MPI uses the most significant bit of the first byte as sign.
+ // Thus 0x1234560000 is compact (0x05123456)
+ // and 0xc0de000000 is compact (0x0600c0de)
+ // (0x05c0de00) would be -0x40de000000
+ //
+ // Bitcoin only uses this "compact" format for encoding difficulty
+ // targets, which are unsigned 256bit quantities. Thus, all the
+ // complexities of the sign bit and using base 256 are probably an
+ // implementation accident.
+ //
+ // This implementation directly uses shifts instead of going
+ // through an intermediate MPI representation.
CBigNum& SetCompact(unsigned int nCompact)
{
unsigned int nSize = nCompact >> 24;
- std::vector<unsigned char> vch(4 + nSize);
- vch[3] = nSize;
- if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
- if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
- if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
- BN_mpi2bn(&vch[0], vch.size(), this);
+ bool fNegative =(nCompact & 0x00800000) != 0;
+ unsigned int nWord = nCompact & 0x007fffff;
+ if (nSize <= 3)
+ {
+ nWord >>= 8*(3-nSize);
+ BN_set_word(this, nWord);
+ }
+ else
+ {
+ BN_set_word(this, nWord);
+ BN_lshift(this, this, 8*(nSize-3));
+ }
+ BN_set_negative(this, fNegative);
return *this;
}
unsigned int GetCompact() const
{
- unsigned int nSize = BN_bn2mpi(this, NULL);
- std::vector<unsigned char> vch(nSize);
- nSize -= 4;
- BN_bn2mpi(this, &vch[0]);
- unsigned int nCompact = nSize << 24;
- if (nSize >= 1) nCompact |= (vch[4] << 16);
- if (nSize >= 2) nCompact |= (vch[5] << 8);
- if (nSize >= 3) nCompact |= (vch[6] << 0);
+ unsigned int nSize = BN_num_bytes(this);
+ unsigned int nCompact = 0;
+ if (nSize <= 3)
+ nCompact = BN_get_word(this) << 8*(3-nSize);
+ else
+ {
+ CBigNum bn;
+ BN_rshift(&bn, this, 8*(nSize-3));
+ nCompact = BN_get_word(&bn);
+ }
+ // The 0x00800000 bit denotes the sign.
+ // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
+ if (nCompact & 0x00800000)
+ {
+ nCompact >>= 8;
+ nSize++;
+ }
+ nCompact |= nSize << 24;
+ nCompact |= (BN_is_negative(this) ? 0x00800000 : 0);
return nCompact;
}
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 07b616438e..41850d8bb8 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -254,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()
@@ -769,7 +771,7 @@ void ThreadRPCServer2(void* parg)
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;
}
@@ -860,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;
}
@@ -1215,6 +1217,9 @@ 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]);
+ if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
return params;
}
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index dc4dc303a8..44050ae1bb 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -177,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..4d2096ef07 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -30,6 +30,7 @@ namespace Checkpoints
(134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
(168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
(193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
+ (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
;
static MapCheckpoints mapCheckpointsTestnet =
@@ -39,6 +40,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 +52,9 @@ namespace Checkpoints
int GetTotalBlocksEstimate()
{
+ if (!GetBoolArg("-checkpoints", true))
+ return 0;
+
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
return checkpoints.rbegin()->first;
@@ -55,6 +62,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/hash.h b/src/hash.h
new file mode 100644
index 0000000000..bc013139bb
--- /dev/null
+++ b/src/hash.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// 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.
+#ifndef BITCOIN_HASH_H
+#define BITCOIN_HASH_H
+
+#include "uint256.h"
+#include "serialize.h"
+
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+
+template<typename T1>
+inline uint256 Hash(const T1 pbegin, const T1 pend)
+{
+ static unsigned char pblank[1];
+ uint256 hash1;
+ SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
+ uint256 hash2;
+ SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
+ return hash2;
+}
+
+class CHashWriter
+{
+private:
+ SHA256_CTX ctx;
+
+public:
+ int nType;
+ int nVersion;
+
+ void Init() {
+ SHA256_Init(&ctx);
+ }
+
+ CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {
+ Init();
+ }
+
+ CHashWriter& write(const char *pch, size_t size) {
+ SHA256_Update(&ctx, pch, size);
+ return (*this);
+ }
+
+ // invalidates the object
+ uint256 GetHash() {
+ uint256 hash1;
+ SHA256_Final((unsigned char*)&hash1, &ctx);
+ uint256 hash2;
+ SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
+ return hash2;
+ }
+
+ template<typename T>
+ CHashWriter& operator<<(const T& obj) {
+ // Serialize to this stream
+ ::Serialize(*this, obj, nType, nVersion);
+ return (*this);
+ }
+};
+
+
+template<typename T1, typename T2>
+inline uint256 Hash(const T1 p1begin, const T1 p1end,
+ const T2 p2begin, const T2 p2end)
+{
+ static unsigned char pblank[1];
+ uint256 hash1;
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
+ SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
+ SHA256_Final((unsigned char*)&hash1, &ctx);
+ uint256 hash2;
+ SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
+ return hash2;
+}
+
+template<typename T1, typename T2, typename T3>
+inline uint256 Hash(const T1 p1begin, const T1 p1end,
+ const T2 p2begin, const T2 p2end,
+ const T3 p3begin, const T3 p3end)
+{
+ static unsigned char pblank[1];
+ uint256 hash1;
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
+ SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
+ SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0]));
+ SHA256_Final((unsigned char*)&hash1, &ctx);
+ uint256 hash2;
+ SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
+ return hash2;
+}
+
+template<typename T>
+uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
+{
+ CHashWriter ss(nType, nVersion);
+ ss << obj;
+ return ss.GetHash();
+}
+
+inline uint160 Hash160(const std::vector<unsigned char>& vch)
+{
+ uint256 hash1;
+ SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
+ uint160 hash2;
+ RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
+ return hash2;
+}
+
+#endif
diff --git a/src/init.cpp b/src/init.cpp
index 06f7359f80..eb3222fff1 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>
@@ -209,17 +211,16 @@ 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, unsigned int flags) {
if (!(flags & BF_EXPLICIT) && IsLimited(addr))
return false;
@@ -257,6 +258,7 @@ 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 " + _("Only accept block chain matching built-in checkpoints (default: 1)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\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" +
@@ -299,7 +301,7 @@ std::string HelpMessage()
" -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" +
" -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" +
+ " -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" +
@@ -344,10 +346,8 @@ void ThreadImport(void *data) {
if (fReindex) {
CImportingNow imp;
int nFile = 0;
- while (!fShutdown) {
- CDiskBlockPos pos;
- pos.nFile = nFile;
- pos.nPos = 0;
+ while (!fRequestShutdown) {
+ CDiskBlockPos pos(nFile, 0);
FILE *file = OpenBlockFile(pos, true);
if (!file)
break;
@@ -355,7 +355,7 @@ void ThreadImport(void *data) {
LoadExternalBlockFile(file, &pos);
nFile++;
}
- if (!fShutdown) {
+ if (!fRequestShutdown) {
pblocktree->WriteReindexing(false);
fReindex = false;
printf("Reindexing finished\n");
@@ -364,7 +364,7 @@ void ThreadImport(void *data) {
// hardcoded $DATADIR/bootstrap.dat
filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
- if (filesystem::exists(pathBootstrap) && !fShutdown) {
+ if (filesystem::exists(pathBootstrap) && !fRequestShutdown) {
FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
if (file) {
CImportingNow imp;
@@ -377,7 +377,7 @@ void ThreadImport(void *data) {
// -loadblock=
BOOST_FOREACH(boost::filesystem::path &path, import->vFiles) {
- if (fShutdown)
+ if (fRequestShutdown)
break;
FILE *file = fopen(path.string().c_str(), "rb");
if (file) {
@@ -482,6 +482,7 @@ bool AppInit2()
// ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug");
+ fBenchmark = GetBoolArg("-benchmark");
// -debug implies fDebug*
if (fDebug)
@@ -570,7 +571,7 @@ bool AppInit2()
printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
if (!fLogTimestamps)
- printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ printf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", GetTime()).c_str());
printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
printf("Used data directory %s\n", strDataDir.c_str());
std::ostringstream strErrors;
@@ -608,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"));
@@ -808,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";
@@ -866,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);
@@ -914,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/key.h b/src/key.h
index 2a2723bbee..4da16b9cdb 100644
--- a/src/key.h
+++ b/src/key.h
@@ -11,7 +11,7 @@
#include "allocators.h"
#include "serialize.h"
#include "uint256.h"
-#include "util.h"
+#include "hash.h"
#include <openssl/ec.h> // for EC_KEY definition
diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform
index dd982236fd..566d1f83a4 100755
--- a/src/leveldb/build_detect_platform
+++ b/src/leveldb/build_detect_platform
@@ -119,6 +119,16 @@ case "$TARGET_OS" in
PLATFORM_EXTRALIBS="-lboost_system-mt-s -lboost_filesystem-mt-s -lboost_thread_win32-mt-s"
CROSS_COMPILE=true
;;
+ NATIVE_WINDOWS)
+ PLATFORM=OS_WINDOWS
+ COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DBOOST_THREAD_USE_LIB"
+ PLATFORM_CXXFLAGS=""
+ PLATFORM_LDFLAGS=""
+ PLATFORM_SHARED_CFLAGS=""
+ PLATFORM_SOURCES="port/port_win.cc util/env_boost.cc util/win_logger.cc"
+ PLATFORM_EXTRALIBS="-lboost_system-mgw45-mt-s-1_50 -lboost_filesystem-mgw45-mt-s-1_50 -lboost_thread-mgw45-mt-s-1_50 -lboost_chrono-mgw45-mt-s-1_50"
+ CROSS_COMPILE=true
+ ;;
*)
echo "Unknown platform!" >&2
exit 1
diff --git a/src/main.cpp b/src/main.cpp
index 808c213d63..96bdabd586 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -42,6 +42,7 @@ set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain
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
@@ -818,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
{
@@ -826,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);
@@ -835,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);
@@ -998,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))
@@ -1059,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();
@@ -1169,11 +1187,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
}
printf("InvalidChainFound: invalid block=%s height=%d work=%s date=%s\n",
BlockHashStr(pindexNew->GetBlockHash()).c_str(), pindexNew->nHeight,
- pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S",
+ pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%Y-%m-%dT%H:%M:%S",
pindexNew->GetBlockTime()).c_str());
printf("InvalidChainFound: current best=%s height=%d work=%s date=%s\n",
BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(),
- DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
+ DateTimeStrFormat("%Y-%m-%dT%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");
}
@@ -1198,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
@@ -1223,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;
@@ -1233,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());
@@ -1518,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);
@@ -1571,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"));
@@ -1607,7 +1634,11 @@ 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));
@@ -1650,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
@@ -1670,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))
@@ -1703,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))
+ int64 nStart = GetTimeMicros();
+ if (!block.DisconnectBlock(pindex, view))
return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
- if (!viewTemp.Flush())
- return error("SetBestBlock() : Cache flush failed after disconnect");
+ if (fBenchmark)
+ printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
- // Queue memory transactions to resurrect
+ // 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);
}
@@ -1721,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", 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() > nCoinCacheSize) {
+ if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) {
FlushBlockFile();
pblocktree->Sync();
- if (!view.Flush())
+ if (!pcoinsTip->Flush())
return false;
}
@@ -1759,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)
@@ -1782,7 +1828,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
nTransactionsUpdated++;
printf("SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s\n",
BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx,
- DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
+ DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", pindexBest->GetBlockTime()).c_str());
// Check the version of the last 100 blocks to see if we need to upgrade:
if (!fIsInitialDownload)
@@ -1874,6 +1920,7 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh
nLastBlockFile = pos.nFile;
infoLastBlockFile.SetNull();
pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile);
+ fUpdatedLast = true;
}
} else {
while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
@@ -1895,12 +1942,16 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh
unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
unsigned int nNewChunks = (infoLastBlockFile.nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
if (nNewChunks > nOldChunks) {
- FILE *file = OpenBlockFile(pos);
- if (file) {
- printf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile);
- AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos);
- fclose(file);
+ 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");
}
}
@@ -1937,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);
- fclose(file);
+ 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);
+ }
}
+ else
+ return error("FindUndoPos() : out of disk space");
}
return true;
@@ -2067,12 +2122,8 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
// Write block to history file
unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
- if (dbp == NULL) {
- if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
- return error("AcceptBlock() : out of disk space");
- } else {
+ if (dbp != NULL)
blockPos = *dbp;
- }
if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
return error("AcceptBlock() : FindBlockPos failed");
if (dbp == NULL)
@@ -2202,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;
}
@@ -2299,13 +2350,18 @@ bool static LoadBlockIndexDB()
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;
@@ -2319,15 +2375,7 @@ bool static LoadBlockIndexDB()
}
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
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);
-
- // Check whether we need to continue reindexing
- bool fReindexing = false;
- pblocktree->ReadReindexing(fReindexing);
- fReindex |= fReindexing;
+ DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", pindexBest->GetBlockTime()).c_str());
// Verify blocks in the best chain
int nCheckLevel = GetArg("-checklevel", 1);
@@ -2490,7 +2538,7 @@ void PrintBlockTree()
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
pindex->nHeight,
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
- DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
+ DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size());
PrintWallets(block);
@@ -2529,7 +2577,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
uint64 nRewind = blkdat.GetPos();
- while (blkdat.good() && !blkdat.eof() && !fShutdown) {
+ 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
@@ -3072,6 +3120,7 @@ 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), BlockHashStr(hashStop).c_str());
@@ -3685,7 +3734,6 @@ public:
CBlock* CreateNewBlock(CReserveKey& reservekey)
{
-
// Create new block
auto_ptr<CBlock> pblock(new CBlock());
if (!pblock.get())
@@ -3735,6 +3783,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
// 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;
@@ -3881,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());
diff --git a/src/main.h b/src/main.h
index 8327141266..8bceffbaf9 100644
--- a/src/main.h
+++ b/src/main.h
@@ -89,6 +89,7 @@ extern std::set<CWallet*> setpwalletRegistered;
extern unsigned char pchMessageStart[4];
extern bool fImporting;
extern bool fReindex;
+extern bool fBenchmark;
extern unsigned int nCoinCacheSize;
// Settings
@@ -151,7 +152,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits);
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) */
+/** Check whether we are doing an initial 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);
@@ -192,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);
}
@@ -1071,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
@@ -1083,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();
}
@@ -1107,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
@@ -1144,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
{
@@ -1229,7 +1258,7 @@ public:
return true;
}
- bool ReadFromDisk(const CDiskBlockPos &pos, bool fReadTransactions = true)
+ bool ReadFromDisk(const CDiskBlockPos &pos)
{
SetNull();
@@ -1237,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 {
@@ -1285,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);
@@ -1450,7 +1477,7 @@ public:
nNonce = 0;
}
- CBlockIndex(CBlock& block)
+ CBlockIndex(CBlockHeader& block)
{
phashBlock = NULL;
pprev = NULL;
@@ -1476,8 +1503,7 @@ public:
if (nStatus & BLOCK_HAVE_DATA) {
ret.nFile = nFile;
ret.nPos = nDataPos;
- } else
- ret.SetNull();
+ }
return ret;
}
@@ -1486,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();
@@ -1637,7 +1662,7 @@ public:
uint256 GetBlockHash() const
{
- CBlock block;
+ CBlockHeader block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
@@ -1814,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);
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 64268dd0aa..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 && 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 ..
+ @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 85d63e9ceb..22d65d6703 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -96,8 +96,8 @@ 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 9629545c0a..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 653f512e82..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.h b/src/net.h
index c43e438d5a..e37953772e 100644
--- a/src/net.h
+++ b/src/net.h
@@ -18,6 +18,7 @@
#include "netbase.h"
#include "protocol.h"
#include "addrman.h"
+#include "hash.h"
class CNode;
class CBlockIndex;
@@ -305,7 +306,8 @@ public:
- void BeginMessage(const char* pszCommand)
+ // TODO: Document the postcondition of this function. Is cs_vSend locked?
+ void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
{
ENTER_CRITICAL_SECTION(cs_vSend);
if (nHeaderStart != -1)
@@ -317,7 +319,8 @@ public:
printf("sending: %s ", pszCommand);
}
- void AbortMessage()
+ // TODO: Document the precondition of this function. Is cs_vSend locked?
+ void AbortMessage() UNLOCK_FUNCTION(cs_vSend)
{
if (nHeaderStart < 0)
return;
@@ -330,7 +333,8 @@ public:
printf("(aborted)\n");
}
- void EndMessage()
+ // TODO: Document the precondition of this function. Is cs_vSend locked?
+ void EndMessage() UNLOCK_FUNCTION(cs_vSend)
{
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
@@ -362,19 +366,6 @@ public:
LEAVE_CRITICAL_SECTION(cs_vSend);
}
- void EndMessageAbortIfEmpty()
- {
- if (nHeaderStart < 0)
- return;
- int nSize = vSend.size() - nMessageStart;
- if (nSize > 0)
- EndMessage();
- else
- AbortMessage();
- }
-
-
-
void PushVersion();
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 9e7307204a..4f31ce9cf3 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -6,6 +6,7 @@
#include "netbase.h"
#include "util.h"
#include "sync.h"
+#include "hash.h"
#ifndef WIN32
#include <sys/fcntl.h>
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/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/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 0198a92c05..9cd22ed297 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
@@ -353,12 +354,17 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
// 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)));
@@ -366,8 +372,8 @@ 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);
@@ -381,8 +387,8 @@ 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);
@@ -406,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();
@@ -437,8 +453,6 @@ void BitcoinGUI::createTrayIcon()
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
#endif
-
- notificator = new Notificator(qApp->applicationName(), trayIcon);
}
#ifndef Q_OS_MAC
@@ -592,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)
@@ -648,39 +697,33 @@ void BitcoinGUI::askFee(qint64 nFeeRequired, bool *payFee)
*payFee = (retval == QMessageBox::Yes);
}
-void BitcoinGUI::incomingTransaction(const QModelIndex & parent, int start, int end)
+void BitcoinGUI::incomingTransaction(const QModelIndex& parent, int start, int /*end*/)
{
- if(!walletModel || !clientModel)
+ // Prevent balloon-spam when initial block download is in progress
+ if(!walletModel || !clientModel || clientModel->inInitialBlockDownload())
return;
+
TransactionTableModel *ttm = walletModel->getTransactionTableModel();
+
+ QString date = ttm->index(start, TransactionTableModel::Date, parent)
+ .data().toString();
qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
- .data(Qt::EditRole).toULongLong();
- if(!clientModel->inInitialBlockDownload())
- {
- // On new transaction, make an info balloon
- // Unless the initial block download is in progress, to prevent balloon-spam
- QString date = ttm->index(start, TransactionTableModel::Date, parent)
+ .data(Qt::EditRole).toULongLong();
+ QString type = ttm->index(start, TransactionTableModel::Type, parent)
+ .data().toString();
+ QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
.data().toString();
- QString type = ttm->index(start, TransactionTableModel::Type, parent)
- .data().toString();
- QString address = ttm->index(start, TransactionTableModel::ToAddress, parent)
- .data().toString();
- QIcon icon = qvariant_cast<QIcon>(ttm->index(start,
- TransactionTableModel::ToAddress, parent)
- .data(Qt::DecorationRole));
- notificator->notify(Notificator::Information,
- (amount)<0 ? tr("Sent transaction") :
- tr("Incoming transaction"),
- tr("Date: %1\n"
- "Amount: %2\n"
- "Type: %3\n"
- "Address: %4\n")
- .arg(date)
- .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
- .arg(type)
- .arg(address), icon);
- }
+ // On new transaction, make an info balloon
+ message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"),
+ tr("Date: %1\n"
+ "Amount: %2\n"
+ "Type: %3\n"
+ "Address: %4\n")
+ .arg(date)
+ .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), amount, true))
+ .arg(type)
+ .arg(address), CClientUIInterface::MSG_INFORMATION);
}
void BitcoinGUI::gotoOverviewPage()
@@ -772,7 +815,8 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
if (nValidUrisFound)
gotoSendCoinsPage();
else
- notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."));
+ message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
+ CClientUIInterface::ICON_WARNING);
}
event->acceptProposedAction();
@@ -799,7 +843,8 @@ void BitcoinGUI::handleURI(QString strURI)
gotoSendCoinsPage();
}
else
- notificator->notify(Notificator::Warning, tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."));
+ message(tr("URI handling"), tr("URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
+ CClientUIInterface::ICON_WARNING);
}
void BitcoinGUI::setEncryptionStatus(int status)
@@ -849,8 +894,12 @@ void BitcoinGUI::backupWallet()
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
if(!filename.isEmpty()) {
if(!walletModel->backupWallet(filename)) {
- QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."));
+ message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."),
+ CClientUIInterface::MSG_ERROR);
}
+ else
+ message(tr("Backup Successful"), tr("The wallet data was successfully saved to the new location."),
+ CClientUIInterface::MSG_INFORMATION);
}
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 8b4607d3ed..b7afdb1c8c 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -105,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 */
@@ -119,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.
@@ -161,7 +168,7 @@ private slots:
The new items are those between start and end inclusive, under the given parent item.
*/
- void incomingTransaction(const QModelIndex & parent, int start, int end);
+ void incomingTransaction(const QModelIndex& parent, int start, int /*end*/);
/** Encrypt the wallet */
void encryptWallet(bool status);
/** Backup the wallet */
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 9b7362d757..ce112803f8 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -84,7 +84,7 @@ 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);
}
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 7d6401ab25..1afccb7859 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -70,8 +70,8 @@ signals:
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/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/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index e3c9413f1b..5dac5a6c45 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -137,7 +137,11 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
case MinimizeToTray:
return QVariant(fMinimizeToTray);
case MapPortUPnP:
+#ifdef USE_UPNP
return settings.value("fUseUPnP", GetBoolArg("-upnp", true));
+#else
+ return QVariant(false);
+#endif
case MinimizeOnClose:
return QVariant(fMinimizeOnClose);
case ProxyUse: {
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/rpcdump.cpp b/src/rpcdump.cpp
index 55d5d79e23..77cef02736 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -34,15 +34,21 @@ public:
Value importprivkey(const Array& params, bool fHelp)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
- "importprivkey <bitcoinprivkey> [label]\n"
+ "importprivkey <bitcoinprivkey> [label] [rescan=true]\n"
"Adds a private key (as returned by dumpprivkey) to your wallet.");
string strSecret = params[0].get_str();
string strLabel = "";
if (params.size() > 1)
strLabel = params[1].get_str();
+
+ // Whether to perform rescan after import
+ bool fRescan = true;
+ if (params.size() > 2)
+ fRescan = params[2].get_bool();
+
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret);
@@ -61,9 +67,11 @@ Value importprivkey(const Array& params, bool fHelp)
if (!pwalletMain->AddKey(key))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
-
- pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
- pwalletMain->ReacceptWalletTransactions();
+
+ if (fRescan) {
+ pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
+ pwalletMain->ReacceptWalletTransactions();
+ }
}
return Value::null;
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 5ebab755b7..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;
@@ -1228,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;
}
@@ -1496,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/serialize.h b/src/serialize.h
index 9e14666fac..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) \
diff --git a/src/sync.h b/src/sync.h
index e80efbe001..930c9b2b80 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -9,15 +9,36 @@
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
+#include "threadsafety.h"
+// Template mixin that adds -Wthread-safety locking annotations to a
+// subset of the mutex API.
+template <typename PARENT>
+class LOCKABLE AnnotatedMixin : public PARENT
+{
+public:
+ void lock() EXCLUSIVE_LOCK_FUNCTION()
+ {
+ PARENT::lock();
+ }
+ void unlock() UNLOCK_FUNCTION()
+ {
+ PARENT::unlock();
+ }
+ bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
+ {
+ return PARENT::try_lock();
+ }
+};
/** Wrapped boost mutex: supports recursive locking, but no waiting */
-typedef boost::recursive_mutex CCriticalSection;
+// TODO: We should move away from using the recursive lock by default.
+typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
/** Wrapped boost mutex: supports waiting but not recursive locking */
-typedef boost::mutex CWaitableCriticalSection;
+typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
#ifdef DEBUG_LOCKORDER
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
@@ -37,46 +58,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 +101,6 @@ public:
{
return lock.owns_lock();
}
-
- boost::unique_lock<Mutex> &GetLock()
- {
- return lock;
- }
};
typedef CMutexLock<CCriticalSection> CCriticalBlock;
diff --git a/src/test/bignum_tests.cpp b/src/test/bignum_tests.cpp
index 744681871f..5b898d1499 100644
--- a/src/test/bignum_tests.cpp
+++ b/src/test/bignum_tests.cpp
@@ -122,4 +122,57 @@ BOOST_AUTO_TEST_CASE(bignum_setint64)
}
}
+
+BOOST_AUTO_TEST_CASE(bignum_SetCompact)
+{
+ CBigNum num;
+ num.SetCompact(0);
+ BOOST_CHECK_EQUAL(num.GetHex(), "0");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0);
+
+ num.SetCompact(0x00123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "0");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0);
+
+ num.SetCompact(0x01123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "12");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x01120000);
+
+ // Make sure that we don't generate compacts with the 0x00800000 bit set
+ num = 0x80;
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x02008000);
+
+ num.SetCompact(0x01fedcba);
+ BOOST_CHECK_EQUAL(num.GetHex(), "-7e");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x01fe0000);
+
+ num.SetCompact(0x02123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "1234");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x02123400);
+
+ num.SetCompact(0x03123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "123456");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x03123456);
+
+ num.SetCompact(0x04123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "12345600");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x04123456);
+
+ num.SetCompact(0x04923456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "-12345600");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x04923456);
+
+ num.SetCompact(0x05009234);
+ BOOST_CHECK_EQUAL(num.GetHex(), "92340000");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x05009234);
+
+ num.SetCompact(0x20123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "1234560000000000000000000000000000000000000000000000000000000000");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0x20123456);
+
+ num.SetCompact(0xff123456);
+ BOOST_CHECK_EQUAL(num.GetHex(), "123456000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ BOOST_CHECK_EQUAL(num.GetCompact(), 0xff123456);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index e4ba0259ba..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,11 +16,15 @@ 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();
+ 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);
@@ -36,6 +42,7 @@ struct TestingSetup {
delete pcoinsdbview;
delete pblocktree;
bitdb.Flush(true);
+ boost::filesystem::remove_all(pathTemp);
}
};
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 3a4c035a30..c47d25bbe9 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -104,11 +104,11 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
BOOST_AUTO_TEST_CASE(util_DateTimeStrFormat)
{
/*These are platform-dependant and thus removed to avoid useless test failures
- BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0), "01/01/70 00:00:00");
- BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 0x7FFFFFFF), "01/19/38 03:14:07");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", 0), "1970-01-01T00:00:00");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", 0x7FFFFFFF), "2038-01-19T03:14:07");
// Formats used within Bitcoin
- BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M:%S", 1317425777), "09/30/11 23:36:17");
- BOOST_CHECK_EQUAL(DateTimeStrFormat("%x %H:%M", 1317425777), "09/30/11 23:36");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", 1317425777), "2011-09-30T23:36:17");
+ BOOST_CHECK_EQUAL(DateTimeStrFormat("%Y-%m-%dT%H:%M", 1317425777), "2011-09-30T23:36");
*/
}
diff --git a/src/threadsafety.h b/src/threadsafety.h
new file mode 100644
index 0000000000..3d3d526fd6
--- /dev/null
+++ b/src/threadsafety.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// 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.
+#ifndef BITCOIN_THREADSAFETY_H
+#define BITCOIN_THREADSAFETY_H
+
+#ifdef __clang__
+// TL;DR Add GUARDED_BY(mutex) to member variables. The others are
+// rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo);
+//
+// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety
+// for documentation. The clang compiler can do advanced static analysis
+// of locking when given the -Wthread-safety option.
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
+#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) __attribute__ ((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+#else
+#define LOCKABLE
+#define SCOPED_LOCKABLE
+#define GUARDED_BY(x)
+#define GUARDED_VAR
+#define PT_GUARDED_BY(x)
+#define PT_GUARDED_VAR
+#define ACQUIRED_AFTER(...)
+#define ACQUIRED_BEFORE(...)
+#define EXCLUSIVE_LOCK_FUNCTION(...)
+#define SHARED_LOCK_FUNCTION(...)
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
+#define SHARED_TRYLOCK_FUNCTION(...)
+#define UNLOCK_FUNCTION(...)
+#define LOCK_RETURNED(x)
+#define LOCKS_EXCLUDED(...)
+#define EXCLUSIVE_LOCKS_REQUIRED(...)
+#define SHARED_LOCKS_REQUIRED(...)
+#define NO_THREAD_SAFETY_ANALYSIS
+#endif // __GNUC__
+#endif // BITCOIN_THREADSAFETY_H
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 03014a5da0..576ba50dbb 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;
@@ -240,7 +240,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
// Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine)
- fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
if (pszFormat[strlen(pszFormat) - 1] == '\n')
fStartedNewLine = true;
else
@@ -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..8bea0dd2b3 100644
--- a/src/util.h
+++ b/src/util.h
@@ -24,9 +24,6 @@ typedef int pid_t; /* define for Windows compatibility */
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <openssl/sha.h>
-#include <openssl/ripemd.h>
-
#include "netbase.h" // for AddTimeData
typedef long long int64;
@@ -132,7 +129,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 +204,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 +327,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;
@@ -407,109 +411,6 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue);
-template<typename T1>
-inline uint256 Hash(const T1 pbegin, const T1 pend)
-{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
-class CHashWriter
-{
-private:
- SHA256_CTX ctx;
-
-public:
- int nType;
- int nVersion;
-
- void Init() {
- SHA256_Init(&ctx);
- }
-
- CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {
- Init();
- }
-
- CHashWriter& write(const char *pch, size_t size) {
- SHA256_Update(&ctx, pch, size);
- return (*this);
- }
-
- // invalidates the object
- uint256 GetHash() {
- uint256 hash1;
- SHA256_Final((unsigned char*)&hash1, &ctx);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
- }
-
- template<typename T>
- CHashWriter& operator<<(const T& obj) {
- // Serialize to this stream
- ::Serialize(*this, obj, nType, nVersion);
- return (*this);
- }
-};
-
-
-template<typename T1, typename T2>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end)
-{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
- SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
- SHA256_Final((unsigned char*)&hash1, &ctx);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
-template<typename T1, typename T2, typename T3>
-inline uint256 Hash(const T1 p1begin, const T1 p1end,
- const T2 p2begin, const T2 p2end,
- const T3 p3begin, const T3 p3end)
-{
- static unsigned char pblank[1];
- uint256 hash1;
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
- SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
- SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0]));
- SHA256_Final((unsigned char*)&hash1, &ctx);
- uint256 hash2;
- SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
-template<typename T>
-uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
-{
- CHashWriter ss(nType, nVersion);
- ss << obj;
- return ss.GetHash();
-}
-
-inline uint160 Hash160(const std::vector<unsigned char>& vch)
-{
- uint256 hash1;
- SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
- uint160 hash2;
- RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
- return hash2;
-}
-
-
/** Median filter over a stream of values.
* Returns the median of the last N numbers
*/
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 3bfb24832b..c07adff6c6 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -756,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))
@@ -957,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()));
+ }
}
}
}
@@ -1310,7 +1312,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
return strError;
}
- if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending...")))
+ if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired))
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
@@ -1770,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 05d60056f4..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
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index e102df9720..4419cbb5f7 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -238,7 +238,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
//printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
//printf(" %12"PRI64d" %s %s %s\n",
// wtx.vout[0].nValue,
- // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
+ // DateTimeStrFormat("%Y-%m-%dT%H:%M:%S", wtx.GetBlockTime()).c_str(),
// wtx.hashBlock.ToString().substr(0,20).c_str(),
// wtx.mapValue["message"].c_str());
}