diff options
54 files changed, 1188 insertions, 662 deletions
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 9f24b55186..3b2de5af3b 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -24,6 +24,8 @@ UI_DIR = build contains(RELEASE, 1) { # Mac: compile for maximum compatibility (10.5, 32-bit) macx:QMAKE_CXXFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk + macx:QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.5 -arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk !windows:!macx { # Linux: static link @@ -344,7 +346,6 @@ isEmpty(BOOST_INCLUDE_PATH) { macx:BOOST_INCLUDE_PATH = /opt/local/include } -windows:LIBS += -lws2_32 -lshlwapi -lmswsock windows:DEFINES += WIN32 windows:RC_FILE = src/qt/res/bitcoin-qt.rc @@ -379,7 +380,7 @@ INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH $$ LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB_PATH,,-L,) $$join(QRENCODE_LIB_PATH,,-L,) LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX # -lgdi32 has to happen after -lcrypto (see #681) -windows:LIBS += -lole32 -luuid -lgdi32 +windows:LIBS += -lws2_32 -lshlwapi -lmswsock -lole32 -loleaut32 -luuid -lgdi32 LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX windows:LIBS += -lboost_chrono$$BOOST_LIB_SUFFIX diff --git a/doc/build-osx.txt b/doc/build-osx.txt index af16162a59..fd878043c0 100644 --- a/doc/build-osx.txt +++ b/doc/build-osx.txt @@ -44,7 +44,7 @@ sudo port install qrencode 4. Now you should be able to build bitcoind: cd bitcoin/src -make -f makefile.osx USE_IPV6=1 +make -f makefile.osx Run: ./bitcoind --help # for a list of command-line options. diff --git a/doc/build-unix.txt b/doc/build-unix.txt index 2e0b53cf77..a1e24ff5d1 100644 --- a/doc/build-unix.txt +++ b/doc/build-unix.txt @@ -36,8 +36,8 @@ turned off by default. Set USE_UPNP to a different value to control this: USE_UPNP=0 (the default) UPnP support turned off by default at runtime USE_UPNP=1 UPnP support turned on by default at runtime -IPv6 support may be enabled by setting: - USE_IPV6=1 Enable IPv6 support +IPv6 support may be disabled by setting: + USE_IPV6=0 Disable IPv6 support Licenses of statically linked libraries: Berkeley DB New BSD license with additional requirement that linked diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst index f6adbd8fdd..b0fdd4d810 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -8,7 +8,11 @@ Debian ------- First, make sure that the required packages for Qt4 development of your -distribution are installed, for Debian and Ubuntu these are: +distribution are installed, these are + +:: + +for Debian and Ubuntu <= 11.10 : :: @@ -16,6 +20,14 @@ distribution are installed, for Debian and Ubuntu these are: libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ libssl-dev libdb4.8++-dev +for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): + +:: + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb++-dev libminiupnpc-dev + then execute the following: :: diff --git a/src/bignum.h b/src/bignum.h index 96b1b2e6ae..ad98613f5f 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -262,28 +262,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 8c04f577d1..bfb696da3d 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() @@ -748,7 +750,8 @@ void ThreadRPCServer2(void* parg) printf("ThreadRPCServer started\n"); strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; - if (mapArgs["-rpcpassword"] == "") + if ((mapArgs["-rpcpassword"] == "") || + (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) { unsigned char rand_pwd[32]; RAND_bytes(rand_pwd, 32); @@ -763,11 +766,12 @@ void ThreadRPCServer2(void* parg) "rpcuser=bitcoinrpc\n" "rpcpassword=%s\n" "(you do not need to remember this password)\n" + "The username and password MUST NOT be the same.\n" "If the file does not exist, create it with owner-readable-only file permissions.\n"), strWhatAmI.c_str(), GetConfigFile().string().c_str(), EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()), - _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL); + "", CClientUIInterface::MSG_ERROR); StartShutdown(); return; } @@ -858,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; } @@ -1213,6 +1217,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "signrawtransaction" && n > 2) ConvertTo<Array>(params[2], true); if (strMethod == "gettxout" && n > 1) ConvertTo<boost::int64_t>(params[1]); if (strMethod == "gettxout" && n > 2) ConvertTo<bool>(params[2]); + if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); + if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 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..279003072e 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -39,6 +39,9 @@ namespace Checkpoints bool CheckBlock(int nHeight, const uint256& hash) { + if (!GetBoolArg("-checkpoints", true)) + return true; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); MapCheckpoints::const_iterator i = checkpoints.find(nHeight); @@ -48,6 +51,9 @@ namespace Checkpoints int GetTotalBlocksEstimate() { + if (!GetBoolArg("-checkpoints", true)) + return 0; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); return checkpoints.rbegin()->first; @@ -55,6 +61,9 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex) { + if (!GetBoolArg("-checkpoints", true)) + return NULL; + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) diff --git a/src/db.cpp b/src/db.cpp index fb405fc277..94629f3cad 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -38,11 +38,13 @@ void CDBEnv::EnvShutdown() if (ret != 0) printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret); if (!fMockDb) - DbEnv(0).remove(GetDataDir().string().c_str(), 0); + DbEnv(0).remove(strPath.c_str(), 0); } CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) { + fDbEnvInit = false; + fMockDb = false; } CDBEnv::~CDBEnv() @@ -55,7 +57,7 @@ void CDBEnv::Close() EnvShutdown(); } -bool CDBEnv::Open(boost::filesystem::path pathEnv_) +bool CDBEnv::Open(const boost::filesystem::path& path) { if (fDbEnvInit) return true; @@ -63,18 +65,17 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_) if (fShutdown) return false; - pathEnv = pathEnv_; - filesystem::path pathDataDir = pathEnv; - filesystem::path pathLogDir = pathDataDir / "database"; + strPath = path.string(); + filesystem::path pathLogDir = path / "database"; filesystem::create_directory(pathLogDir); - filesystem::path pathErrorFile = pathDataDir / "db.log"; + filesystem::path pathErrorFile = path / "db.log"; printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); unsigned int nEnvFlags = 0; if (GetBoolArg("-privdb", true)) nEnvFlags |= DB_PRIVATE; - int nDbCache = GetArg("-dbcache", 25); + unsigned int nDbCache = GetArg("-dbcache", 25); dbenv.set_lg_dir(pathLogDir.string().c_str()); dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); dbenv.set_lg_bsize(1048576); @@ -85,7 +86,7 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_) dbenv.set_flags(DB_AUTO_COMMIT, 1); dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv.open(pathDataDir.string().c_str(), + int ret = dbenv.open(strPath.c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -33,7 +33,7 @@ class CDBEnv private: bool fDbEnvInit; bool fMockDb; - boost::filesystem::path pathEnv; + std::string strPath; void EnvShutdown(); @@ -46,7 +46,7 @@ public: CDBEnv(); ~CDBEnv(); void MakeMock(); - bool IsMock() { return fMockDb; }; + bool IsMock() { return fMockDb; } /* * Verify that database file strFile is OK. If it is not, @@ -66,7 +66,7 @@ public: typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair; bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult); - bool Open(boost::filesystem::path pathEnv_); + bool Open(const boost::filesystem::path &path); void Close(); void Flush(bool fShutdown); void CheckpointLSN(std::string strFile); diff --git a/src/init.cpp b/src/init.cpp index f6df4055fc..7f311fa881 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "txdb.h" #include "walletdb.h" #include "bitcoinrpc.h" @@ -9,6 +10,7 @@ #include "init.h" #include "util.h" #include "ui_interface.h" + #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/convenience.hpp> @@ -28,9 +30,9 @@ CClientUIInterface uiInterface; // Used to pass flags to the Bind() function enum BindFlags { - BF_NONE = 0, - BF_EXPLICIT = 1, - BF_REPORT_ERROR = 2 + BF_NONE = 0, + BF_EXPLICIT = (1U << 0), + BF_REPORT_ERROR = (1U << 1) }; ////////////////////////////////////////////////////////////////////////////// @@ -209,18 +211,17 @@ 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, int flags) { +bool static Bind(const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; std::string strError; @@ -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 " + _("Lock in block chain with compiled-in checkpoints (default: 1)") + "\n" + " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" + " -bind=<addr> " + _("Bind to given address and always listen on it. Use [host]:port notation for IPv6") + "\n" + " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\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) @@ -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/leveldb/Makefile b/src/leveldb/Makefile index 7f658cfdf9..14e494f3ce 100755 --- a/src/leveldb/Makefile +++ b/src/leveldb/Makefile @@ -19,10 +19,10 @@ $(shell ./build_detect_platform build_config.mk) # this file is generated by the previous line to set build flags and sources include build_config.mk -CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) -CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) +xCFLAGS = -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) $(CFLAGS) +xCXXFLAGS = -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) $(CXXFLAGS) -LDFLAGS += $(PLATFORM_LDFLAGS) +xLDFLAGS = $(PLATFORM_LDFLAGS) $(LDFLAGS) LIBOBJECTS = $(SOURCES:.cc=.o) MEMENVOBJECTS = $(MEMENV_SOURCES:.cc=.o) @@ -82,7 +82,7 @@ $(SHARED2): $(SHARED3) endif $(SHARED3): - $(CXX) $(LDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) $(PLATFORM_EXTRALIBS) -o $(SHARED3) + $(CXX) $(xLDFLAGS) $(PLATFORM_SHARED_LDFLAGS)$(SHARED2) $(xCXXFLAGS) $(PLATFORM_SHARED_CFLAGS) $(SOURCES) $(PLATFORM_EXTRALIBS) -o $(SHARED3) endif # PLATFORM_SHARED_EXT @@ -100,74 +100,74 @@ $(LIBRARY): $(LIBOBJECTS) $(AR) -rs $@ $(LIBOBJECTS) db_bench: db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/db_bench.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) db_bench_sqlite3: doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) -lsqlite3 + $(CXX) doc/bench/db_bench_sqlite3.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) -lsqlite3 db_bench_tree_db: doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) - $(CXX) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) -lkyotocabinet + $(CXX) doc/bench/db_bench_tree_db.o $(LIBOBJECTS) $(TESTUTIL) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) -lkyotocabinet arena_test: util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) util/arena_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) bloom_test: util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) util/bloom_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) c_test: db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) corruption_test: db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/corruption_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) db_test: db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/db_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) dbformat_test: db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/dbformat_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) env_test: util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) util/env_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) filename_test: db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/filename_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) filter_block_test: table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) table/filter_block_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) log_test: db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/log_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) table/table_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) version_edit_test: db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/version_edit_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) version_set_test: db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/version_set_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) - $(CXX) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) $(MEMENVLIBRARY) : $(MEMENVOBJECTS) rm -f $@ $(AR) -rs $@ $(MEMENVOBJECTS) memenv_test : helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) - $(CXX) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(LDFLAGS) $(PLATFORM_EXTRALIBS) + $(CXX) helpers/memenv/memenv_test.o $(MEMENVLIBRARY) $(LIBRARY) $(TESTHARNESS) -o $@ $(xLDFLAGS) $(PLATFORM_EXTRALIBS) ifeq ($(PLATFORM), IOS) # For iOS, create universal object files to be used on both the simulator and @@ -179,22 +179,22 @@ IOSVERSION=$(shell defaults read $(PLATFORMSROOT)/iPhoneOS.platform/version CFBu .cc.o: mkdir -p ios-x86/$(dir $@) - $(SIMULATORROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ + $(SIMULATORROOT)/usr/bin/$(CXX) $(xCXXFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ mkdir -p ios-arm/$(dir $@) - $(DEVICEROOT)/usr/bin/$(CXX) $(CXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ + $(DEVICEROOT)/usr/bin/$(CXX) $(xCXXFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ lipo ios-x86/$@ ios-arm/$@ -create -output $@ .c.o: mkdir -p ios-x86/$(dir $@) - $(SIMULATORROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ + $(SIMULATORROOT)/usr/bin/$(CC) $(xCFLAGS) -isysroot $(SIMULATORROOT)/SDKs/iPhoneSimulator$(IOSVERSION).sdk -arch i686 -c $< -o ios-x86/$@ mkdir -p ios-arm/$(dir $@) - $(DEVICEROOT)/usr/bin/$(CC) $(CFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ + $(DEVICEROOT)/usr/bin/$(CC) $(xCFLAGS) -isysroot $(DEVICEROOT)/SDKs/iPhoneOS$(IOSVERSION).sdk -arch armv6 -arch armv7 -c $< -o ios-arm/$@ lipo ios-x86/$@ ios-arm/$@ -create -output $@ else .cc.o: - $(CXX) $(CXXFLAGS) -c $< -o $@ + $(CXX) $(xCXXFLAGS) -c $< -o $@ .c.o: - $(CC) $(CFLAGS) -c $< -o $@ + $(CC) $(xCFLAGS) -c $< -o $@ endif diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index dd982236fd..b16a3aae7c 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/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index 654a4b9d3d..6ca352e2ca 100644 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -21,13 +21,20 @@ #else #define PLATFORM_IS_LITTLE_ENDIAN false #endif -#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\ +#elif defined(OS_FREEBSD) + #include <sys/types.h> + #include <sys/endian.h> + #define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN) +#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\ defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID) #include <sys/types.h> #include <sys/endian.h> +#elif defined(OS_HPUX) + #define PLATFORM_IS_LITTLE_ENDIAN false #else #include <endian.h> #endif + #include <pthread.h> #ifdef SNAPPY #include <snappy.h> @@ -42,7 +49,7 @@ #if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\ defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\ - defined(OS_ANDROID) + defined(OS_ANDROID) || defined(OS_HPUX) // Use fread/fwrite/fflush on platforms without _unlocked variants #define fread_unlocked fread #define fwrite_unlocked fwrite diff --git a/src/main.cpp b/src/main.cpp index 0940260f9e..61bd6b7b87 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 @@ -719,7 +720,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, // are the actual inputs available? if (!tx.HaveInputs(view)) return error("CTxMemPool::accept() : inputs already spent"); - + // Bring the best block into scope view.GetBestBlock(); @@ -771,7 +772,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!tx.CheckInputs(view, CS_ALWAYS, true, false)) + if (!tx.CheckInputs(view, CS_ALWAYS, SCRIPT_VERIFY_P2SH)) { return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } @@ -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(); @@ -1168,11 +1186,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew) uiInterface.NotifyBlocksChanged(); } printf("InvalidChainFound: invalid block=%s height=%d work=%s date=%s\n", - pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, + BlockHashStr(pindexNew->GetBlockHash()).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexNew->GetBlockTime()).c_str()); printf("InvalidChainFound: current best=%s height=%d work=%s date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), + BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6) printf("InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); @@ -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()); @@ -1327,7 +1348,7 @@ bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const return true; } -bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmode, bool fStrictPayToScriptHash, bool fStrictEncodings) const +bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmode, unsigned int flags) const { if (!IsCoinBase()) { @@ -1338,7 +1359,7 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod // While checking, GetBestBlock() refers to the parent block. // This is also true for mempool checks. - int nSpendHeight = inputs.GetBestBlock()->nHeight + 1; + int nSpendHeight = inputs.GetBestBlock()->nHeight + 1; int64 nValueIn = 0; int64 nFees = 0; for (unsigned int i = 0; i < vin.size(); i++) @@ -1384,7 +1405,7 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, enum CheckSig_mode csmod const CCoins &coins = inputs.GetCoins(prevout.hash); // Verify signature - if (!VerifySignature(coins, *this, i, fStrictPayToScriptHash, fStrictEncodings, 0)) + if (!VerifySignature(coins, *this, i, flags, 0)) return DoS(100,error("CheckInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str())); } } @@ -1415,7 +1436,7 @@ bool CTransaction::ClientCheckInputs() const return false; // Verify signature - if (!VerifySignature(CCoins(txPrev, -1), *this, i, true, false, 0)) + if (!VerifySignature(CCoins(txPrev, -1), *this, i, SCRIPT_VERIFY_P2SH, 0)) return error("ConnectInputs() : VerifySignature failed"); ///// this is redundant with the mempool.mapNextTx stuff, @@ -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")); @@ -1598,7 +1625,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust nFees += tx.GetValueIn(view)-tx.GetValueOut(); - if (!tx.CheckInputs(view, CS_AFTER_CHECKPOINT, fStrictPayToScriptHash, false)) + if (!tx.CheckInputs(view, CS_AFTER_CHECKPOINT, fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE)) return false; } @@ -1607,10 +1634,14 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust return error("ConnectBlock() : UpdateInputs failed"); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); + } + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) - return false; + return error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)); if (fJustCheck) return true; @@ -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)) @@ -1693,8 +1726,8 @@ bool SetBestChain(CBlockIndex* pindexNew) reverse(vConnect.begin(), vConnect.end()); if (vDisconnect.size() > 0) { - printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); - printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), BlockHashStr(pfork->GetBlockHash()).c_str(), BlockHashStr(pindexBest->GetBlockHash()).c_str()); + printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), BlockHashStr(pfork->GetBlockHash()).c_str(), BlockHashStr(pindexNew->GetBlockHash()).c_str()); } // Disconnect shorter branch @@ -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)) - return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after disconnect"); - - // Queue memory transactions to resurrect + int64 nStart = GetTimeMicros(); + if (!block.DisconnectBlock(pindex, view)) + return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); + if (fBenchmark) + printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); + + // Queue memory transactions to resurrect. + // We only do this for blocks after the last checkpoint (reorganisation before that + // point should only happen with -reindex/-loadblock, or a misbehaving peer. BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!tx.IsCoinBase()) + if (!tx.IsCoinBase() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate()) vResurrect.push_back(tx); } @@ -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", pindex->GetBlockHash().ToString().substr(0,20).c_str()); + return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str()); } - if (!viewTemp.Flush()) - return error("SetBestBlock() : Cache flush failed after connect"); + if (fBenchmark) + printf("- Connect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); // Queue memory transactions to delete BOOST_FOREACH(const CTransaction& tx, block.vtx) vDelete.push_back(tx); } + // Flush changes to global coin state + int64 nStart = GetTimeMicros(); + int nModified = view.GetCacheSize(); + if (!view.Flush()) + return error("SetBestBlock() : unable to modify coin state"); + int64 nTime = GetTimeMicros() - nStart; + if (fBenchmark) + printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified); + // Make sure it's successfully written to disk before changing memory structure bool fIsInitialDownload = IsInitialBlockDownload(); - if (!fIsInitialDownload || view.GetCacheSize() > 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) @@ -1781,7 +1827,7 @@ bool SetBestChain(CBlockIndex* pindexNew) nTimeBestReceived = GetTime(); nTransactionsUpdated++; printf("SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx, + BlockHashStr(hashBestChain).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), (unsigned long)pindexNew->nChainTx, DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // Check the version of the last 100 blocks to see if we need to upgrade: @@ -1819,7 +1865,7 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos) // Check for duplicate uint256 hash = GetHash(); if (mapBlockIndex.count(hash)) - return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str()); + return error("AddToBlockIndex() : %s already exists", BlockHashStr(hash).c_str()); // Construct new block index object CBlockIndex* pindexNew = new CBlockIndex(*this); @@ -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); + 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); + } } - 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); + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenUndoFile(pos); + if (file) { + printf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } } - fclose(file); + else + return error("FindUndoPos() : out of disk space"); } return true; @@ -2018,62 +2073,57 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp) CBlockIndex* pindexPrev = NULL; int nHeight = 0; if (hash != hashGenesisBlock) { - - map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock); - if (mi == mapBlockIndex.end()) - return DoS(10, error("AcceptBlock() : prev block not found")); - pindexPrev = (*mi).second; - nHeight = pindexPrev->nHeight+1; - - // Check proof of work - if (nBits != GetNextWorkRequired(pindexPrev, this)) - return DoS(100, error("AcceptBlock() : incorrect proof of work")); - - // Check timestamp against prev - if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return error("AcceptBlock() : block's timestamp is too early"); - - // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, vtx) - if (!tx.IsFinal(nHeight, GetBlockTime())) - return DoS(10, error("AcceptBlock() : contains a non-final transaction")); - - // Check that the block chain matches the known block chain up to a checkpoint - if (!Checkpoints::CheckBlock(nHeight, hash)) - return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); - - // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (nVersion < 2) - { - if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || - (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock); + if (mi == mapBlockIndex.end()) + return DoS(10, error("AcceptBlock() : prev block not found")); + pindexPrev = (*mi).second; + nHeight = pindexPrev->nHeight+1; + + // Check proof of work + if (nBits != GetNextWorkRequired(pindexPrev, this)) + return DoS(100, error("AcceptBlock() : incorrect proof of work")); + + // Check timestamp against prev + if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) + return error("AcceptBlock() : block's timestamp is too early"); + + // Check that all transactions are finalized + BOOST_FOREACH(const CTransaction& tx, vtx) + if (!tx.IsFinal(nHeight, GetBlockTime())) + return DoS(10, error("AcceptBlock() : contains a non-final transaction")); + + // Check that the block chain matches the known block chain up to a checkpoint + if (!Checkpoints::CheckBlock(nHeight, hash)) + return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); + + // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: + if (nVersion < 2) { - return error("AcceptBlock() : rejected nVersion=1 block"); + if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || + (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) + { + return error("AcceptBlock() : rejected nVersion=1 block"); + } } - } - // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (nVersion >= 2) - { - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || - (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) + // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height + if (nVersion >= 2) { - CScript expect = CScript() << nHeight; - if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) - return DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); + // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): + if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || + (fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) + { + CScript expect = CScript() << nHeight; + if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + return DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); + } } } - } // Write block to history file unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); 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) @@ -2112,9 +2162,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) // Check for duplicate uint256 hash = pblock->GetHash(); if (mapBlockIndex.count(hash)) - return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str()); + return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, BlockHashStr(hash).c_str()); if (mapOrphanBlocks.count(hash)) - return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str()); + return error("ProcessBlock() : already have block (orphan) %s", BlockHashStr(hash).c_str()); // Preliminary checks if (!pblock->CheckBlock()) @@ -2147,7 +2197,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) // If we don't already have its previous block, shunt it off to holding area until we get it if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock)) { - printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); + printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", BlockHashStr(pblock->hashPrevBlock).c_str()); // Accept orphans as long as there is a node to request its parents from if (pfrom) { @@ -2203,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; } @@ -2300,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,17 +2374,9 @@ bool static LoadBlockIndexDB() pindex = pindexPrev; } printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n", - hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, + BlockHashStr(hashBestChain).c_str(), nBestHeight, DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - // Load bnBestInvalidWork, OK if it doesn't exist - pblocktree->ReadBestInvalidWork(bnBestInvalidWork); - - // Check whether we need to continue reindexing - bool fReindexing = false; - pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; - // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); @@ -2530,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 @@ -3029,12 +3076,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (pindex) pindex = pindex->pnext; int nLimit = 500; - printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit); + printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), BlockHashStr(hashStop).c_str(), nLimit); for (; pindex; pindex = pindex->pnext) { if (pindex->GetBlockHash() == hashStop) { - printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str()); + printf(" getblocks stopping at %d %s\n", pindex->nHeight, BlockHashStr(pindex->GetBlockHash()).c_str()); break; } pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); @@ -3042,7 +3089,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { // When this block is requested, we'll send an inv that'll make them // getblocks the next batch of inventory. - printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str()); + printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, BlockHashStr(pindex->GetBlockHash()).c_str()); pfrom->hashContinue = pindex->GetBlockHash(); break; } @@ -3073,9 +3120,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pindex = pindex->pnext; } + // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end vector<CBlock> vHeaders; int nLimit = 2000; - printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str()); + printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), BlockHashStr(hashStop).c_str()); for (; pindex; pindex = pindex->pnext) { vHeaders.push_back(pindex->GetBlockHeader()); @@ -3159,7 +3207,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CBlock block; vRecv >> block; - printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str()); + printf("received block %s\n", BlockHashStr(block.GetHash()).c_str()); // block.print(); CInv inv(MSG_BLOCK, block.GetHash()); @@ -3686,7 +3734,6 @@ public: CBlock* CreateNewBlock(CReserveKey& reservekey) { - // Create new block auto_ptr<CBlock> pblock(new CBlock()); if (!pblock.get()) @@ -3736,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; @@ -3864,7 +3912,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; - if (!tx.CheckInputs(viewTemp, CS_ALWAYS, true, false)) + if (!tx.CheckInputs(viewTemp, CS_ALWAYS, SCRIPT_VERIFY_P2SH)) continue; CTxUndo txundo; @@ -3882,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 e346726045..fdaec3469e 100644 --- a/src/main.h +++ b/src/main.h @@ -22,7 +22,7 @@ class CAddress; class CInv; class CNode; -class CBlockIndexWorkComparator; +struct CBlockIndexWorkComparator; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 1000000; @@ -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 @@ -174,6 +175,11 @@ CBlockIndex * InsertBlockIndex(uint256 hash); +static inline std::string BlockHashStr(const uint256& hash) +{ + return hash.ToString(); +} + bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); class CDiskBlockPos @@ -187,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); } @@ -625,7 +640,7 @@ public: // Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) // This does not modify the UTXO set - bool CheckInputs(CCoinsViewCache &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true) const; + bool CheckInputs(CCoinsViewCache &view, enum CheckSig_mode csmode, unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC) const; // Apply the effects of this transaction on the UTXO set represented by view bool UpdateCoins(CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const; @@ -733,7 +748,6 @@ public: bool WriteToDisk(CDiskBlockPos &pos) { - // Open history file to append CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) @@ -746,7 +760,7 @@ public: // Write undo data long fileOutPos = ftell(fileout); if (fileOutPos < 0) - return error("CBlock::WriteToDisk() : ftell failed"); + return error("CBlockUndo::WriteToDisk() : ftell failed"); pos.nPos = (unsigned int)fileOutPos; fileout << *this; @@ -757,7 +771,6 @@ public: return true; } - }; /** pruned version of CTransaction: only retains metadata and unspent transaction outputs @@ -1068,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 @@ -1080,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(); } @@ -1104,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 @@ -1141,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 { @@ -1226,7 +1258,7 @@ public: return true; } - bool ReadFromDisk(const CDiskBlockPos &pos, bool fReadTransactions = true) + bool ReadFromDisk(const CDiskBlockPos &pos) { SetNull(); @@ -1234,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 { @@ -1257,9 +1287,9 @@ public: void print() const { printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", - GetHash().ToString().substr(0,20).c_str(), + BlockHashStr(GetHash()).c_str(), nVersion, - hashPrevBlock.ToString().substr(0,20).c_str(), + BlockHashStr(hashPrevBlock).c_str(), hashMerkleRoot.ToString().substr(0,10).c_str(), nTime, nBits, nNonce, vtx.size()); @@ -1282,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); @@ -1447,7 +1477,7 @@ public: nNonce = 0; } - CBlockIndex(CBlock& block) + CBlockIndex(CBlockHeader& block) { phashBlock = NULL; pprev = NULL; @@ -1473,8 +1503,7 @@ public: if (nStatus & BLOCK_HAVE_DATA) { ret.nFile = nFile; ret.nPos = nDataPos; - } else - ret.SetNull(); + } return ret; } @@ -1483,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(); @@ -1570,7 +1598,7 @@ public: return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)", pprev, pnext, nHeight, hashMerkleRoot.ToString().substr(0,10).c_str(), - GetBlockHash().ToString().substr(0,20).c_str()); + BlockHashStr(GetBlockHash()).c_str()); } void print() const @@ -1634,7 +1662,7 @@ public: uint256 GetBlockHash() const { - CBlock block; + CBlockHeader block; block.nVersion = nVersion; block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; @@ -1651,7 +1679,7 @@ public: str += CBlockIndex::ToString(); str += strprintf("\n hashBlock=%s, hashPrev=%s)", GetBlockHash().ToString().c_str(), - hashPrev.ToString().substr(0,20).c_str()); + BlockHashStr(hashPrev).c_str()); return str; } @@ -1811,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); @@ -1872,7 +1901,7 @@ public: virtual bool GetStats(CCoinsStats &stats); // As we use CCoinsViews polymorphically, have a virtual destructor - virtual ~CCoinsView() {}; + virtual ~CCoinsView() {} }; /** CCoinsView backed by another CCoinsView */ 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: @@ -67,12 +67,6 @@ void SetReachable(enum Network net, bool fFlag = true); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); -enum -{ - MSG_TX = 1, - MSG_BLOCK, -}; - /** Thread types */ enum threadId { diff --git a/src/noui.cpp b/src/noui.cpp index db25f2d285..204e76aba7 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -2,20 +2,37 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "ui_interface.h" #include "init.h" #include "bitcoinrpc.h" #include <string> -static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) +static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) { + std::string strCaption; + // Check for usage of predefined caption + switch (style) { + case CClientUIInterface::MSG_ERROR: + strCaption += _("Error"); + break; + case CClientUIInterface::MSG_WARNING: + strCaption += _("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + strCaption += _("Information"); + break; + default: + strCaption += caption; // Use supplied caption + } + printf("%s: %s\n", caption.c_str(), message.c_str()); - fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str()); return 4; } -static bool noui_ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption) +static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/) { return true; } diff --git a/src/protocol.cpp b/src/protocol.cpp index d6e340e366..23969e5b97 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -6,6 +6,7 @@ #include "protocol.h" #include "util.h" #include "netbase.h" +#include "main.h" #ifndef WIN32 # include <arpa/inet.h> @@ -140,6 +141,11 @@ const char* CInv::GetCommand() const std::string CInv::ToString() const { + if (type == MSG_BLOCK) + return strprintf("%s %s", GetCommand(), BlockHashStr(hash).c_str()); + if (type == MSG_TX) + return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,10).c_str()); + return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,20).c_str()); } diff --git a/src/protocol.h b/src/protocol.h index 36f8b144cd..96fd197ecd 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -134,4 +134,10 @@ class CInv uint256 hash; }; +enum +{ + MSG_TX = 1, + MSG_BLOCK, +}; + #endif // __INCLUDED_PROTOCOL_H__ diff --git a/src/qt/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..3fe86501f6 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -25,6 +25,7 @@ #include "notificator.h" #include "guiutil.h" #include "rpcconsole.h" +#include "ui_interface.h" #ifdef Q_OS_MAC #include "macdockiconhandler.h" @@ -89,7 +90,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): // Create the toolbars createToolBars(); - // Create the tray icon (or setup the dock icon) + // Create system tray icon and notification createTrayIcon(); // Create tabs @@ -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) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 8b4607d3ed..3faf6d948c 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. diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 7e8e102ee7..497c05976b 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -13,26 +13,33 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "rpcuser=bitcoinrpc\n" "rpcpassword=%s\n" "(you do not need to remember this password)\n" +"The username and password MUST NOT be the same.\n" "If the file does not exist, create it with owner-readable-only file " "permissions.\n"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:" "@STRENGTH)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"An error occurred while setting up the RPC port %u for listening on IPv4: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "An error occurred while setting up the RPC port %u for listening on IPv6, " "falling back to IPv4: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"An error occurred while setting up the RPC port %u for listening on IPv4: %s"), +"Bind to given address and always listen on it. Use [host]:port notation for " +"IPv6"), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Cannot obtain a lock on data directory %s. Bitcoin is probably already " +"Cannot obtain a lock on data directory %s. Bitcoin is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Error: The transaction was rejected. This might happen if some of the coins " +"Error initializing database environment %s! To recover, BACKUP THAT " +"DIRECTORY, then remove everything from it except for wallet.dat."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: The transaction was rejected! This might happen if some of the coins " "in your wallet were already spent, such as if you used a copy of wallet.dat " "and coins were spent in the copy but not marked as spent here."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: This transaction requires a transaction fee of at least %s because of " -"its amount, complexity, or use of recently received funds "), +"its amount, complexity, or use of recently received funds!"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Execute command when the best block changes (%s in cmd is replaced by block " "hash)"), @@ -45,6 +52,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Set maximum size of high-priority/low-fee transactions in bytes (default: " "27000)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"This is a pre-release test build - use at your own risk - do not use for " +"mining or merchant applications"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Unable to bind to %s on this computer. Bitcoin is probably already running."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: -paytxfee is set very high! This is the transaction fee you will " @@ -56,6 +66,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: Please check that your computer's date and time are correct! If " "your clock is wrong Bitcoin will not work properly."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: error reading wallet.dat! All keys read correctly, but transaction " +"data or address book entries might be missing or incorrect."), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as " +"wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect " +"you should restore from a backup."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "You must set rpcpassword=<password> in the configuration file:\n" "%s\n" "If the file does not exist, create it with owner-readable-only file " @@ -65,7 +82,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Accept connections from outside (default: 1 i QT_TRANSLATE_NOOP("bitcoin-core", "Add a node to connect to and attempt to keep the connection open"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow DNS lookups for -addnode, -seednode and -connect"), QT_TRANSLATE_NOOP("bitcoin-core", "Allow JSON-RPC connections from specified IP address"), -QT_TRANSLATE_NOOP("bitcoin-core", "Bind to given address. Use [host]:port notation for IPv6"), +QT_TRANSLATE_NOOP("bitcoin-core", "Attempt to recover private keys from a corrupt wallet.dat"), QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin version"), QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin"), QT_TRANSLATE_NOOP("bitcoin-core", "Block creation options:"), @@ -85,8 +102,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin"), QT_TRANSLATE_NOOP("bitcoin-core", "Error"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed "), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction "), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"), @@ -96,8 +113,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"), QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"), QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"), QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-6, default: 1)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Importing blockchain data file."), -QT_TRANSLATE_NOOP("bitcoin-core", "Importing bootstrap blockchain data file."), +QT_TRANSLATE_NOOP("bitcoin-core", "Importing blocks from block database..."), QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000?.dat file"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), @@ -118,6 +134,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Output extra debugging information. Implies a QT_TRANSLATE_NOOP("bitcoin-core", "Output extra network debugging information"), QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"), QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp"), +QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild blockchain index from current blk000??.dat files"), QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"), QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."), QT_TRANSLATE_NOOP("bitcoin-core", "Run in the background as a daemon and accept commands"), @@ -131,7 +148,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Sending..."), QT_TRANSLATE_NOOP("bitcoin-core", "Server certificate file (default: server.cert)"), QT_TRANSLATE_NOOP("bitcoin-core", "Server private key (default: server.pem)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set database cache size in megabytes (default: 25)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Set database disk log size in megabytes (default: 100)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set key pool size to <n> (default: 100)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set maximum block size in bytes (default: 250000)"), QT_TRANSLATE_NOOP("bitcoin-core", "Set minimum block size in bytes (default: 0)"), @@ -155,7 +171,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Use UPnP to map the listening port (default: QT_TRANSLATE_NOOP("bitcoin-core", "Use proxy to reach tor hidden services (default: same as -proxy)"), QT_TRANSLATE_NOOP("bitcoin-core", "Use the test network"), QT_TRANSLATE_NOOP("bitcoin-core", "Username for JSON-RPC connections"), +QT_TRANSLATE_NOOP("bitcoin-core", "Verifying database integrity..."), QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart Bitcoin to complete"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: Disk space is low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: This version is obsolete, upgrade required!"), +QT_TRANSLATE_NOOP("bitcoin-core", "wallet.dat corrupt, salvage failed"), };
\ No newline at end of file diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 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/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index ee9967e15d..c70ea652de 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -300,17 +300,17 @@ This product includes software developed by the OpenSSL Project for use in the O <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+257"/> + <location filename="../bitcoingui.cpp" line="+266"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+237"/> + <location line="+241"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-299"/> + <location line="-309"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -320,7 +320,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Show general overview of wallet</translation> </message> <message> - <location line="+17"/> + <location line="+20"/> <source>&Transactions</source> <translation>&Transactions</translation> </message> @@ -330,7 +330,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Browse transaction history</translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>&Address Book</source> <translation>&Address Book</translation> </message> @@ -340,7 +340,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Edit the list of stored addresses and labels</translation> </message> <message> - <location line="-13"/> + <location line="-15"/> <source>&Receive coins</source> <translation>&Receive coins</translation> </message> @@ -350,12 +350,12 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Show the list of addresses for receiving payments</translation> </message> <message> - <location line="-7"/> + <location line="-8"/> <source>&Send coins</source> <translation>&Send coins</translation> </message> <message> - <location line="+35"/> + <location line="+39"/> <source>E&xit</source> <translation>E&xit</translation> </message> @@ -385,7 +385,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Options...</translation> </message> <message> - <location line="+4"/> + <location line="+5"/> <source>&Encrypt Wallet...</source> <translation>&Encrypt Wallet...</translation> </message> @@ -399,8 +399,18 @@ This product includes software developed by the OpenSSL Project for use in the O <source>&Change Passphrase...</source> <translation>&Change Passphrase...</translation> </message> + <message> + <location line="+246"/> + <source>Importing blocks from disk...</source> + <translation>Importing blocks from disk...</translation> + </message> + <message> + <location line="+3"/> + <source>Reindexing blocks on disk...</source> + <translation>Reindexing blocks on disk...</translation> + </message> <message numerus="yes"> - <location line="+241"/> + <location line="+10"/> <source>~%n block(s) remaining</source> <translation> <numerusform>~%n block remaining</numerusform> @@ -408,37 +418,27 @@ This product includes software developed by the OpenSSL Project for use in the O </translation> </message> <message> - <location line="+6"/> - <source>Downloaded %1 of %2 blocks of transaction history (%3% done).</source> - <translation>Downloaded %1 of %2 blocks of transaction history (%3% done).</translation> - </message> - <message> - <location line="-242"/> + <location line="-252"/> <source>&Export...</source> <translation>&Export...</translation> </message> <message> - <location line="-58"/> + <location line="-65"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> <message> - <location line="+45"/> + <location line="+49"/> <source>Modify configuration options for Bitcoin</source> <translation>Modify configuration options for Bitcoin</translation> </message> <message> - <location line="+14"/> + <location line="+17"/> <source>Export the data in the current tab to a file</source> <translation>Export the data in the current tab to a file</translation> </message> <message> - <location line="-10"/> - <source>Encrypt or decrypt wallet</source> - <translation>Encrypt or decrypt wallet</translation> - </message> - <message> - <location line="+3"/> + <location line="-9"/> <source>Backup wallet to another location</source> <translation>Backup wallet to another location</translation> </message> @@ -448,7 +448,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Change the passphrase used for wallet encryption</translation> </message> <message> - <location line="+6"/> + <location line="+9"/> <source>&Debug window</source> <translation>&Debug window</translation> </message> @@ -458,12 +458,12 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Open debugging and diagnostic console</translation> </message> <message> - <location line="-5"/> + <location line="-7"/> <source>&Verify message...</source> <translation>&Verify message...</translation> </message> <message> - <location line="-186"/> + <location line="-196"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> @@ -473,7 +473,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Wallet</translation> </message> <message> - <location line="+168"/> + <location line="+176"/> <source>&About Bitcoin</source> <translation>&About Bitcoin</translation> </message> @@ -483,7 +483,27 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Show / Hide</translation> </message> <message> - <location line="+39"/> + <location line="+1"/> + <source>Show or hide the main Window</source> + <translation>Show or hide the main Window</translation> + </message> + <message> + <location line="+2"/> + <source>Encrypt the private keys that belong to your wallet</source> + <translation>Encrypt the private keys that belong to your wallet</translation> + </message> + <message> + <location line="+7"/> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Sign messages with your Bitcoin addresses to prove you own them</translation> + </message> + <message> + <location line="+2"/> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> + </message> + <message> + <location line="+31"/> <source>&File</source> <translation>&File</translation> </message> @@ -509,12 +529,11 @@ This product includes software developed by the OpenSSL Project for use in the O </message> <message> <location line="+13"/> - <location line="+9"/> + <location line="+10"/> <source>[testnet]</source> <translation>[testnet]</translation> </message> <message> - <location line="+0"/> <location line="+60"/> <source>Bitcoin client</source> <translation>Bitcoin client</translation> @@ -528,12 +547,22 @@ This product includes software developed by the OpenSSL Project for use in the O </translation> </message> <message> - <location line="+40"/> - <source>Downloaded %1 blocks of transaction history.</source> - <translation>Downloaded %1 blocks of transaction history.</translation> + <location line="+45"/> + <source>Processed %1 of %2 blocks of transaction history (%3% done).</source> + <translation>Processed %1 of %2 blocks of transaction history (%3% done).</translation> + </message> + <message> + <location line="+7"/> + <source>Processed %1 blocks of transaction history.</source> + <translation>Processed %1 blocks of transaction history.</translation> + </message> + <message> + <location line="+107"/> + <source>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</source> + <translation>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</translation> </message> <message numerus="yes"> - <location line="+22"/> + <location line="-93"/> <source>%n second(s) ago</source> <translation> <numerusform>%n second ago</numerusform> @@ -580,12 +609,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Last received block was generated %1.</translation> </message> <message> - <location line="+59"/> - <source>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</source> - <translation>This transaction is over the size limit. You can still send it for a fee of %1, which goes to the nodes that process your transaction and helps to support the network. Do you want to pay the fee?</translation> - </message> - <message> - <location line="+5"/> + <location line="+62"/> <source>Confirm transaction fee</source> <translation>Confirm transaction fee</translation> </message> @@ -614,13 +638,13 @@ Address: %4 </message> <message> <location line="+100"/> - <location line="+15"/> + <location line="+27"/> <source>URI handling</source> <translation>URI handling</translation> </message> <message> - <location line="-15"/> - <location line="+15"/> + <location line="-27"/> + <location line="+27"/> <source>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> <translation>URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> </message> @@ -813,16 +837,6 @@ Address: %4 <translation>&Start Bitcoin on system login</translation> </message> <message> - <location line="+7"/> - <source>Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached.</source> - <translation>Detach block and address databases at shutdown. This means they can be moved to another data directory, but it slows down shutdown. The wallet is always detached.</translation> - </message> - <message> - <location line="+3"/> - <source>&Detach databases at shutdown</source> - <translation>&Detach databases at shutdown</translation> - </message> - <message> <location line="+21"/> <source>&Network</source> <translation>&Network</translation> @@ -958,7 +972,7 @@ Address: %4 <translation>default</translation> </message> <message> - <location line="+147"/> + <location line="+146"/> <location line="+9"/> <source>Warning</source> <translation>Warning</translation> @@ -983,7 +997,7 @@ Address: %4 <translation>Form</translation> </message> <message> - <location line="+33"/> + <location line="+52"/> <location line="+183"/> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> <translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation> @@ -1039,7 +1053,7 @@ Address: %4 <translation>Total number of transactions in wallet</translation> </message> <message> - <location filename="../overviewpage.cpp" line="+112"/> + <location filename="../overviewpage.cpp" line="+115"/> <location line="+1"/> <source>out of sync</source> <translation>out of sync</translation> @@ -1120,7 +1134,7 @@ Address: %4 <location line="+53"/> <location line="+23"/> <location line="+23"/> - <location filename="../rpcconsole.cpp" line="+348"/> + <location filename="../rpcconsole.cpp" line="+349"/> <source>N/A</source> <translation>N/A</translation> </message> @@ -1351,8 +1365,8 @@ Address: %4 </message> <message> <location line="+5"/> - <source>Error: Transaction creation failed.</source> - <translation>Error: Transaction creation failed.</translation> + <source>Error: Transaction creation failed!</source> + <translation>Error: Transaction creation failed!</translation> </message> <message> <location line="+5"/> @@ -1378,23 +1392,23 @@ Address: %4 <translation>Pay &To:</translation> </message> <message> - <location line="+24"/> + <location line="+34"/> + <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> + <translation>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> + </message> + <message> + <location line="+60"/> <location filename="../sendcoinsentry.cpp" line="+25"/> <source>Enter a label for this address to add it to your address book</source> <translation>Enter a label for this address to add it to your address book</translation> </message> <message> - <location line="+9"/> + <location line="-78"/> <source>&Label:</source> <translation>&Label:</translation> </message> <message> - <location line="+18"/> - <source>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</source> - <translation>The address to send the payment to (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)</translation> - </message> - <message> - <location line="+10"/> + <location line="+28"/> <source>Choose address from address book</source> <translation>Choose address from address book</translation> </message> @@ -1757,7 +1771,7 @@ Address: %4 <translation>Transaction</translation> </message> <message> - <location line="+5"/> + <location line="+3"/> <source>Inputs</source> <translation>Inputs</translation> </message> @@ -1777,7 +1791,7 @@ Address: %4 <translation>false</translation> </message> <message> - <location line="-211"/> + <location line="-209"/> <source>, has not been successfully broadcast yet</source> <translation>, has not been successfully broadcast yet</translation> </message> @@ -2099,32 +2113,32 @@ Address: %4 <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+71"/> + <location filename="../bitcoinstrings.cpp" line="+86"/> <source>Bitcoin version</source> <translation>Bitcoin version</translation> </message> <message> - <location line="+82"/> + <location line="+81"/> <source>Usage:</source> <translation>Usage:</translation> </message> <message> - <location line="-25"/> + <location line="-24"/> <source>Send command to -server or bitcoind</source> <translation>Send command to -server or bitcoind</translation> </message> <message> - <location line="-19"/> + <location line="-20"/> <source>List commands</source> <translation>List commands</translation> </message> <message> - <location line="-11"/> + <location line="-10"/> <source>Get help for a command</source> <translation>Get help for a command</translation> </message> <message> - <location line="+20"/> + <location line="+19"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -2139,7 +2153,7 @@ Address: %4 <translation>Specify pid file (default: bitcoind.pid)</translation> </message> <message> - <location line="-47"/> + <location line="-46"/> <source>Generate coins</source> <translation>Generate coins</translation> </message> @@ -2149,21 +2163,16 @@ Address: %4 <translation>Don't generate coins</translation> </message> <message> - <location line="+60"/> + <location line="+59"/> <source>Specify data directory</source> <translation>Specify data directory</translation> </message> <message> - <location line="-8"/> + <location line="-7"/> <source>Set database cache size in megabytes (default: 25)</source> <translation>Set database cache size in megabytes (default: 25)</translation> </message> <message> - <location line="+1"/> - <source>Set database disk log size in megabytes (default: 100)</source> - <translation>Set database disk log size in megabytes (default: 100)</translation> - </message> - <message> <location line="-26"/> <source>Listen for connections on <port> (default: 8333 or testnet: 18333)</source> <translation>Listen for connections on <port> (default: 8333 or testnet: 18333)</translation> @@ -2174,86 +2183,116 @@ Address: %4 <translation>Maintain at most <n> connections to peers (default: 125)</translation> </message> <message> - <location line="-33"/> + <location line="-32"/> <source>Connect to a node to retrieve peer addresses, and disconnect</source> <translation>Connect to a node to retrieve peer addresses, and disconnect</translation> </message> <message> - <location line="+64"/> + <location line="+63"/> <source>Specify your own public address</source> <translation>Specify your own public address</translation> </message> <message> - <location line="-75"/> - <source>Bind to given address. Use [host]:port notation for IPv6</source> - <translation>Bind to given address. Use [host]:port notation for IPv6</translation> - </message> - <message> - <location line="+77"/> + <location line="+2"/> <source>Threshold for disconnecting misbehaving peers (default: 100)</source> <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation> </message> <message> - <location line="-104"/> + <location line="-113"/> <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> <translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation> </message> <message> - <location line="-19"/> + <location line="-26"/> <source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source> <translation>An error occurred while setting up the RPC port %u for listening on IPv4: %s</translation> </message> <message> - <location line="+5"/> - <source>Detach block and address databases. Increases shutdown time (default: 0)</source> - <translation>Detach block and address databases. Increases shutdown time (default: 0)</translation> - </message> - <message> - <location line="+12"/> + <location line="+24"/> <source>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</source> <translation>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</translation> </message> <message> - <location line="+24"/> + <location line="+34"/> <source>Accept command line and JSON-RPC commands</source> <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="+36"/> - <source>Importing blockchain data file.</source> - <translation>Importing blockchain data file.</translation> - </message> - <message> - <location line="+1"/> - <source>Importing bootstrap blockchain data file.</source> - <translation>Importing bootstrap blockchain data file.</translation> - </message> - <message> - <location line="+23"/> + <location line="+60"/> <source>Run in the background as a daemon and accept commands</source> <translation>Run in the background as a daemon and accept commands</translation> </message> <message> - <location line="+33"/> + <location line="+32"/> <source>Use the test network</source> <translation>Use the test network</translation> </message> <message> - <location line="-92"/> + <location line="-91"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> <message> - <location line="-45"/> + <location line="-72"/> + <source>%s, you must set a rpcpassword in the configuration file: + %s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions. +</source> + <translation>%s, you must set a rpcpassword in the configuration file: + %s +It is recommended you use the following random password: +rpcuser=bitcoinrpc +rpcpassword=%s +(you do not need to remember this password) +The username and password MUST NOT be the same. +If the file does not exist, create it with owner-readable-only file permissions.</translation> + </message> + <message> + <location line="+15"/> <source>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</source> <translation>An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s</translation> </message> <message> - <location line="+25"/> + <location line="+3"/> + <source>Bind to given address and always listen on it. Use [host]:port notation for IPv6</source> + <translation>Bind to given address and always listen on it. Use [host]:port notation for IPv6</translation> + </message> + <message> + <location line="+3"/> + <source>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</source> + <translation>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</translation> + </message> + <message> + <location line="+3"/> + <source>Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat.</source> + <translation>Error initializing database environment %s! To recover, BACKUP THAT DIRECTORY, then remove everything from it except for wallet.dat.</translation> + </message> + <message> + <location line="+3"/> + <source>Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</source> + <translation>Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</translation> + </message> + <message> + <location line="+4"/> + <source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</source> + <translation>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!</translation> + </message> + <message> + <location line="+11"/> <source>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</source> <translation>Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)</translation> </message> <message> + <location line="+3"/> + <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> + <translation>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> + </message> + <message> <location line="+5"/> <source>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</source> <translation>Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.</translation> @@ -2269,7 +2308,22 @@ Address: %4 <translation>Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly.</translation> </message> <message> - <location line="+16"/> + <location line="+3"/> + <source>Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> + <translation>Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</translation> + </message> + <message> + <location line="+3"/> + <source>Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup.</source> + <translation>Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup.</translation> + </message> + <message> + <location line="+14"/> + <source>Attempt to recover private keys from a corrupt wallet.dat</source> + <translation>Attempt to recover private keys from a corrupt wallet.dat</translation> + </message> + <message> + <location line="+3"/> <source>Block creation options:</source> <translation>Block creation options:</translation> </message> @@ -2284,7 +2338,17 @@ Address: %4 <translation>Discover own IP address (default: 1 when listening and no -externalip)</translation> </message> <message> - <location line="+11"/> + <location line="+8"/> + <source>Error: Transaction creation failed!</source> + <translation>Error: Transaction creation failed!</translation> + </message> + <message> + <location line="+1"/> + <source>Error: Wallet locked, unable to create transaction!</source> + <translation>Error: Wallet locked, unable to create transaction!</translation> + </message> + <message> + <location line="+2"/> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> </message> @@ -2294,7 +2358,12 @@ Address: %4 <translation>Find peers using DNS lookup (default: 1 unless -connect)</translation> </message> <message> - <location line="+11"/> + <location line="+6"/> + <source>Importing blocks from block database...</source> + <translation>Importing blocks from block database...</translation> + </message> + <message> + <location line="+4"/> <source>Invalid -tor address: '%s'</source> <translation>Invalid -tor address: '%s'</translation> </message> @@ -2329,6 +2398,11 @@ Address: %4 <translation>Prepend debug output with timestamp</translation> </message> <message> + <location line="+1"/> + <source>Rebuild blockchain index from current blk000??.dat files</source> + <translation>Rebuild blockchain index from current blk000??.dat files</translation> + </message> + <message> <location line="+4"/> <source>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source> <translation>SSL options: (see the Bitcoin Wiki for SSL setup instructions)</translation> @@ -2349,7 +2423,7 @@ Address: %4 <translation>Send trace/debug info to debugger</translation> </message> <message> - <location line="+7"/> + <location line="+6"/> <source>Set maximum block size in bytes (default: 250000)</source> <translation>Set maximum block size in bytes (default: 250000)</translation> </message> @@ -2389,6 +2463,11 @@ Address: %4 <translation>Username for JSON-RPC connections</translation> </message> <message> + <location line="+1"/> + <source>Verifying database integrity...</source> + <translation>Verifying database integrity...</translation> + </message> + <message> <location line="+2"/> <source>Warning: Disk space is low!</source> <translation>Warning: Disk space is low!</translation> @@ -2399,12 +2478,17 @@ Address: %4 <translation>Warning: This version is obsolete, upgrade required!</translation> </message> <message> - <location line="-41"/> + <location line="+1"/> + <source>wallet.dat corrupt, salvage failed</source> + <translation>wallet.dat corrupt, salvage failed</translation> + </message> + <message> + <location line="-43"/> <source>Password for JSON-RPC connections</source> <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-52"/> + <location line="-51"/> <source>Allow JSON-RPC connections from specified IP address</source> <translation>Allow JSON-RPC connections from specified IP address</translation> </message> @@ -2414,12 +2498,12 @@ Address: %4 <translation>Send commands to node running on <ip> (default: 127.0.0.1)</translation> </message> <message> - <location line="-91"/> + <location line="-101"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+114"/> + <location line="+123"/> <source>Upgrade wallet to latest format</source> <translation>Upgrade wallet to latest format</translation> </message> @@ -2429,7 +2513,7 @@ Address: %4 <translation>Set key pool size to <n> (default: 100)</translation> </message> <message> - <location line="-14"/> + <location line="-13"/> <source>Rescan the block chain for missing wallet transactions</source> <translation>Rescan the block chain for missing wallet transactions</translation> </message> @@ -2444,7 +2528,7 @@ Address: %4 <translation>How thorough the block verification is (0-6, default: 1)</translation> </message> <message> - <location line="+3"/> + <location line="+2"/> <source>Imports blocks from external blk000?.dat file</source> <translation>Imports blocks from external blk000?.dat file</translation> </message> @@ -2454,7 +2538,7 @@ Address: %4 <translation>Use OpenSSL (https) for JSON-RPC connections</translation> </message> <message> - <location line="-21"/> + <location line="-20"/> <source>Server certificate file (default: server.cert)</source> <translation>Server certificate file (default: server.cert)</translation> </message> @@ -2464,32 +2548,27 @@ Address: %4 <translation>Server private key (default: server.pem)</translation> </message> <message> - <location line="-116"/> + <location line="-130"/> <source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source> <translation>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</translation> </message> <message> - <location line="+128"/> + <location line="+141"/> <source>This help message</source> <translation>This help message</translation> </message> <message> - <location line="-120"/> - <source>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</source> - <translation>Cannot obtain a lock on data directory %s. Bitcoin is probably already running.</translation> - </message> - <message> - <location line="+46"/> + <location line="-73"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="+77"/> + <location line="+76"/> <source>Unable to bind to %s on this computer (bind returned error %d, %s)</source> <translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation> </message> <message> - <location line="-69"/> + <location line="-68"/> <source>Connect through socks proxy</source> <translation>Connect through socks proxy</translation> </message> @@ -2499,12 +2578,12 @@ Address: %4 <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+43"/> + <location line="+42"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> <message> - <location line="-26"/> + <location line="-25"/> <source>Error loading blkindex.dat</source> <translation>Error loading blkindex.dat</translation> </message> @@ -2529,7 +2608,7 @@ Address: %4 <translation>Error loading wallet.dat</translation> </message> <message> - <location line="+19"/> + <location line="+18"/> <source>Invalid -proxy address: '%s'</source> <translation>Invalid -proxy address: '%s'</translation> </message> @@ -2544,7 +2623,7 @@ Address: %4 <translation>Unknown -socks proxy version requested: %i</translation> </message> <message> - <location line="-74"/> + <location line="-73"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -2554,42 +2633,22 @@ Address: %4 <translation>Cannot resolve -externalip address: '%s'</translation> </message> <message> - <location line="+30"/> + <location line="+29"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</translation> </message> <message> - <location line="-15"/> + <location line="-14"/> <source>Error: could not start node</source> <translation>Error: could not start node</translation> </message> <message> - <location line="-1"/> - <source>Error: Wallet locked, unable to create transaction </source> - <translation>Error: Wallet locked, unable to create transaction </translation> - </message> - <message> - <location line="-56"/> - <source>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds </source> - <translation>Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds </translation> - </message> - <message> - <location line="+55"/> - <source>Error: Transaction creation failed </source> - <translation>Error: Transaction creation failed </translation> - </message> - <message> - <location line="+42"/> + <location line="+40"/> <source>Sending...</source> <translation>Sending...</translation> </message> <message> - <location line="-101"/> - <source>Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</source> - <translation>Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</translation> - </message> - <message> - <location line="+77"/> + <location line="-25"/> <source>Invalid amount</source> <translation>Invalid amount</translation> </message> @@ -2604,17 +2663,17 @@ Address: %4 <translation>Loading block index...</translation> </message> <message> - <location line="-45"/> + <location line="-44"/> <source>Add a node to connect to and attempt to keep the connection open</source> <translation>Add a node to connect to and attempt to keep the connection open</translation> </message> <message> - <location line="-18"/> + <location line="-25"/> <source>Unable to bind to %s on this computer. Bitcoin is probably already running.</source> <translation>Unable to bind to %s on this computer. Bitcoin is probably already running.</translation> </message> <message> - <location line="+47"/> + <location line="+54"/> <source>Find peers using internet relay chat (default: 0)</source> <translation>Find peers using internet relay chat (default: 0)</translation> </message> @@ -2624,12 +2683,12 @@ Address: %4 <translation>Fee per KB to add to transactions you send</translation> </message> <message> - <location line="+19"/> + <location line="+18"/> <source>Loading wallet...</source> <translation>Loading wallet...</translation> </message> <message> - <location line="-39"/> + <location line="-38"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> @@ -2654,31 +2713,12 @@ Address: %4 <translation>Done loading</translation> </message> <message> - <location line="+64"/> + <location line="+63"/> <source>To use the %s option</source> <translation>To use the %s option</translation> </message> <message> - <location line="-139"/> - <source>%s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. -</source> - <translation>%s, you must set a rpcpassword in the configuration file: - %s -It is recommended you use the following random password: -rpcuser=bitcoinrpc -rpcpassword=%s -(you do not need to remember this password) -If the file does not exist, create it with owner-readable-only file permissions. -</translation> - </message> - <message> - <location line="+80"/> + <location line="-58"/> <source>Error</source> <translation>Error</translation> </message> diff --git a/src/qt/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/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 2b8a0c049b..3dc32d0e47 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -15,12 +15,11 @@ #include <openssl/crypto.h> +// TODO: add a scrollback limit, as there is currently none // TODO: make it possible to filter out categories (esp debug messages when implemented) // TODO: receive errors and debug messages through ClientModel -const int CONSOLE_SCROLLBACK = 50; const int CONSOLE_HISTORY = 50; - const QSize ICON_SIZE(24, 24); const struct { @@ -289,6 +288,8 @@ static QString categoryClass(int category) void RPCConsole::clear() { ui->messagesWidget->clear(); + history.clear(); + historyPtr = 0; ui->lineEdit->clear(); ui->lineEdit->setFocus(); diff --git a/src/qt/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/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index e82f4ad91d..9531b12678 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -505,7 +505,7 @@ Value signrawtransaction(const Array& params, bool fHelp) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, true, 0)) + if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)) fComplete = false; } diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 29b3298b99..90a68f560a 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -3,14 +3,18 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <boost/assign/list_of.hpp> + #include "wallet.h" #include "walletdb.h" #include "bitcoinrpc.h" #include "init.h" #include "base58.h" -using namespace json_spirit; using namespace std; +using namespace boost; +using namespace boost::assign; +using namespace json_spirit; int64 nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -573,7 +577,7 @@ Value movecmd(const Array& params, bool fHelp) // Debit CAccountingEntry debit; - debit.nOrderPos = pwalletMain->IncOrderPosNext(); + debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); debit.strAccount = strFrom; debit.nCreditDebit = -nAmount; debit.nTime = nNow; @@ -583,7 +587,7 @@ Value movecmd(const Array& params, bool fHelp) // Credit CAccountingEntry credit; - credit.nOrderPos = pwalletMain->IncOrderPosNext(); + credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb); credit.strAccount = strTo; credit.nCreditDebit = nAmount; credit.nTime = nNow; @@ -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/script.cpp b/src/script.cpp index 36d208c247..f65508aacc 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -314,7 +314,7 @@ bool IsCanonicalSignature(const valtype &vchSig) { return true; } -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, bool fStrictEncodings, int nHashType) +bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); @@ -327,7 +327,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co if (script.size() > 10000) return false; int nOpCount = 0; - + bool fStrictEncodings = flags & SCRIPT_VERIFY_STRICTENC; try { @@ -1637,14 +1637,14 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto } bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType) + unsigned int flags, int nHashType) { vector<vector<unsigned char> > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, fStrictEncodings, nHashType)) + if (!EvalScript(stack, scriptSig, txTo, nIn, flags, nHashType)) return false; - if (fValidatePayToScriptHash) + if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, fStrictEncodings, nHashType)) + if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags, nHashType)) return false; if (stack.empty()) return false; @@ -1653,16 +1653,21 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C return false; // Additional validation for spend-to-script-hash transactions: - if (fValidatePayToScriptHash && scriptPubKey.IsPayToScriptHash()) + if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only return false; // or validation fails + // stackCopy cannot be empty here, because if it was the + // P2SH HASH <> EQUAL scriptPubKey would be evaluated with + // an empty stack and the EvalScript above would return false. + assert(!stackCopy.empty()); + const valtype& pubKeySerialized = stackCopy.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, fStrictEncodings, nHashType)) + if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags, nHashType)) return false; if (stackCopy.empty()) return false; @@ -1705,7 +1710,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CTransa } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, true, true, 0); + return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType) @@ -1718,7 +1723,7 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CTrans return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); } -bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType) +bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { assert(nIn < txTo.vin.size()); const CTxIn& txin = txTo.vin[nIn]; @@ -1726,7 +1731,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in return false; const CTxOut& txout = txFrom.vout[txin.prevout.n]; - return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, fValidatePayToScriptHash, fStrictEncodings, nHashType); + return VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, flags, nHashType); } static CScript PushAll(const vector<valtype>& values) @@ -1844,9 +1849,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign Solver(scriptPubKey, txType, vSolutions); vector<valtype> stack1; - EvalScript(stack1, scriptSig1, CTransaction(), 0, true, 0); + EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); vector<valtype> stack2; - EvalScript(stack2, scriptSig2, CTransaction(), 0, true, 0); + EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC, 0); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); } diff --git a/src/script.h b/src/script.h index f9df587ca3..7b0643f70a 100644 --- a/src/script.h +++ b/src/script.h @@ -26,6 +26,13 @@ enum SIGHASH_ANYONECANPAY = 0x80, }; +/** Script verification flags */ +enum +{ + SCRIPT_VERIFY_NONE = 0, + SCRIPT_VERIFY_P2SH = (1U << 0), + SCRIPT_VERIFY_STRICTENC = (1U << 1), +}; enum txnouttype { @@ -656,7 +663,7 @@ public: bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey); bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig); -bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, bool fStrictEncodings, int nHashType); +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet); int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions); bool IsStandard(const CScript& scriptPubKey); @@ -667,8 +674,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType); -bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType); + unsigned int flags, int nHashType); +bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); // Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, // combine them intelligently and return the result. diff --git a/src/serialize.h b/src/serialize.h index 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 b9c89027bb..930c9b2b80 100644 --- a/src/sync.h +++ b/src/sync.h @@ -58,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) @@ -116,11 +101,6 @@ public: { return lock.owns_lock(); } - - boost::unique_lock<Mutex> &GetLock() - { - return lock; - } }; typedef CMutexLock<CCriticalSection> CCriticalBlock; diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 0db33dcd05..b1e98f65ed 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -230,6 +230,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) key.MakeNewKey(true); CBasicKeyStore keystore; keystore.AddKey(key); + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; // 100 orphan transactions: static const int NPREV=100; @@ -277,7 +278,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) mst1 = boost::posix_time::microsec_clock::local_time(); for (unsigned int i = 0; i < 5; i++) for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, true, true, SIGHASH_ALL)); + BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL)); mst2 = boost::posix_time::microsec_clock::local_time(); msdiff = mst2 - mst1; long nManyValidate = msdiff.total_milliseconds(); @@ -288,13 +289,13 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) // Empty a signature, validation should fail: CScript save = tx.vin[0].scriptSig; tx.vin[0].scriptSig = CScript(); - BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, true, true, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL)); tx.vin[0].scriptSig = save; // Swap signatures, validation should fail: std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); - BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, true, true, SIGHASH_ALL)); - BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, true, true, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(CCoins(orphans[0], MEMPOOL_HEIGHT), tx, 0, flags, SIGHASH_ALL)); + BOOST_CHECK(!VerifySignature(CCoins(orphans[1], MEMPOOL_HEIGHT), tx, 1, flags, SIGHASH_ALL)); std::swap(tx.vin[0].scriptSig, tx.vin[1].scriptSig); // Exercise -maxsigcachesize code: @@ -304,7 +305,7 @@ BOOST_AUTO_TEST_CASE(DoS_checkSig) BOOST_CHECK(SignSignature(keystore, orphans[0], tx, 0)); BOOST_CHECK(tx.vin[0].scriptSig != oldSig); for (unsigned int j = 0; j < tx.vin.size(); j++) - BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, true, true, SIGHASH_ALL)); + BOOST_CHECK(VerifySignature(CCoins(orphans[j], MEMPOOL_HEIGHT), tx, j, flags, SIGHASH_ALL)); mapArgs.erase("-maxsigcachesize"); LimitOrphanTxSize(0); diff --git a/src/test/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/multisig_tests.cpp b/src/test/multisig_tests.cpp index aa6feb7201..7297bb9a75 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -20,8 +20,6 @@ using namespace boost::assign; typedef vector<unsigned char> valtype; extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType); BOOST_AUTO_TEST_SUITE(multisig_tests) @@ -44,6 +42,8 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, BOOST_AUTO_TEST_CASE(multisig_verify) { + unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; + CKey key[4]; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); @@ -80,19 +80,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys.clear(); keys += key[0],key[1]; // magic operator+= from boost.assign s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, true, 0)); + BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags, 0)); for (int i = 0; i < 4; i++) { keys.clear(); keys += key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, true, 0), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 1: %d", i)); keys.clear(); keys += key[1],key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, true, 0), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags, 0), strprintf("a&b 2: %d", i)); } // Test a OR b: @@ -102,16 +102,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys += key[i]; s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i)); else - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0), strprintf("a|b: %d", i)); } s.clear(); s << OP_0 << OP_0; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0)); s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags, 0)); for (int i = 0; i < 4; i++) @@ -121,9 +121,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys += key[i],key[j]; s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, true, 0), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 1: %d %d", i, j)); else - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, true, true, 0), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags, 0), strprintf("escrow 2: %d %d", i, j)); } } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 35069a3fdd..b5107193fd 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -13,8 +13,6 @@ using namespace std; // Test routines internal to script.cpp: extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType); // Helpers: static std::vector<unsigned char> @@ -40,7 +38,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict, true, 0); + return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); } @@ -105,7 +103,7 @@ BOOST_AUTO_TEST_CASE(sign) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = VerifySignature(CCoins(txFrom, 0), txTo[i], 0, true, true, 0); + bool sigOK = VerifySignature(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 3f280ba947..5d5a1525f7 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -20,8 +20,8 @@ using namespace json_spirit; using namespace boost::algorithm; extern uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -extern bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - bool fValidatePayToScriptHash, bool fStrictEncodings, int nHashType); + +static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; CScript ParseScript(string s) @@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(script_valid) CScript scriptPubKey = ParseScript(scriptPubKeyString); CTransaction tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, true, true, SIGHASH_NONE), strTest); + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, flags, SIGHASH_NONE), strTest); } } @@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) CScript scriptPubKey = ParseScript(scriptPubKeyString); CTransaction tx; - BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, true, true, SIGHASH_NONE), strTest); + BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, flags, SIGHASH_NONE), strTest); } } @@ -250,15 +250,15 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) txTo12.vout[0].nValue = 1; CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, true, 0)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags, 0)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, true, true, 0)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, flags, 0)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, flags, 0)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) @@ -286,46 +286,46 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) std::vector<CKey> keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, flags, 0)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, true, true, 0)); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, flags, 0)); } BOOST_AUTO_TEST_CASE(script_combineSigs) diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 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/transaction_tests.cpp b/src/test/transaction_tests.cpp index 4385b9ba37..23837c6c15 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) break; } - BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), false, 0), strTest); + BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0), strTest); } } } @@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) break; } - fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool(), true, 0); + fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], tx, i, test[2].get_bool() ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); } BOOST_CHECK_MESSAGE(!fValid, strTest); diff --git a/src/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..3cbc6b196b 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -64,7 +64,7 @@ bool fDebug = false; bool fDebugNet = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; -bool fRequestShutdown = false; +volatile bool fRequestShutdown = false; bool fShutdown = false; bool fDaemon = false; bool fServer = false; @@ -1248,7 +1248,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) string strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly."); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } } } @@ -1310,6 +1310,28 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif +boost::filesystem::path GetTempPath() { +#if BOOST_FILESYSTEM_VERSION == 3 + return boost::filesystem::temp_directory_path(); +#else + // TODO: remove when we don't support filesystem v2 anymore + boost::filesystem::path path; +#ifdef WIN32 + char pszPath[MAX_PATH] = ""; + + if (GetTempPathA(MAX_PATH, pszPath)) + path = boost::filesystem::path(pszPath); +#else + path = boost::filesystem::path("/tmp"); +#endif + if (path.empty() || !boost::filesystem::is_directory(path)) { + printf("GetTempPath(): failed to find temp path\n"); + return boost::filesystem::path(""); + } + return path; +#endif +} + void runCommand(std::string strCommand) { int nErr = ::system(strCommand.c_str()); diff --git a/src/util.h b/src/util.h index b798f60aa7..ab921e6f05 100644 --- a/src/util.h +++ b/src/util.h @@ -132,7 +132,7 @@ extern bool fDebug; extern bool fDebugNet; extern bool fPrintToConsole; extern bool fPrintToDebugger; -extern bool fRequestShutdown; +extern volatile bool fRequestShutdown; extern bool fShutdown; extern bool fDaemon; extern bool fServer; @@ -207,6 +207,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif +boost::filesystem::path GetTempPath(); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); @@ -329,6 +330,12 @@ inline int64 GetTimeMillis() boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds(); } +inline int64 GetTimeMicros() +{ + return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) - + boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds(); +} + inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime) { time_t n = nTime; diff --git a/src/wallet.cpp b/src/wallet.cpp index ae9f695e9f..c07adff6c6 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -291,10 +291,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } -int64 CWallet::IncOrderPosNext() +int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { - int64 nRet = nOrderPosNext; - CWalletDB(strWalletFile).WriteOrderPosNext(++nOrderPosNext); + int64 nRet = nOrderPosNext++; + if (pwalletdb) { + pwalletdb->WriteOrderPosNext(nOrderPosNext); + } else { + CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); + } return nRet; } @@ -752,7 +756,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) while (pindex) { CBlock block; - block.ReadFromDisk(pindex, true); + block.ReadFromDisk(pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) @@ -926,9 +930,8 @@ int64 CWallet::GetImmatureBalance() const LOCK(cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx& pcoin = (*it).second; - if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.IsInMainChain()) - nTotal += GetCredit(pcoin); + const CWalletTx* pcoin = &(*it).second; + nTotal += pcoin->GetImmatureCredit(); } } return nTotal; @@ -954,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())); + } } } } @@ -1307,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)) @@ -1767,3 +1772,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } + +void CWallet::LockCoin(COutPoint& output) +{ + setLockedCoins.insert(output); +} + +void CWallet::UnlockCoin(COutPoint& output) +{ + setLockedCoins.erase(output); +} + +void CWallet::UnlockAllCoins() +{ + setLockedCoins.clear(); +} + +bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const +{ + COutPoint outpt(hash, n); + + return (setLockedCoins.count(outpt) > 0); +} + +void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) +{ + for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); + it != setLockedCoins.end(); it++) { + COutPoint outpt = (*it); + vOutpts.push_back(outpt); + } +} + diff --git a/src/wallet.h b/src/wallet.h index 43b695c597..ecfdafe2eb 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -119,11 +119,18 @@ public: CPubKey vchDefaultKey; + std::set<COutPoint> setLockedCoins; + // check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const; bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; + bool IsLockedCoin(uint256 hash, unsigned int n) const; + void LockCoin(COutPoint& output); + void UnlockCoin(COutPoint& output); + void UnlockAllCoins(); + void ListLockedCoins(std::vector<COutPoint>& vOutpts); // keystore implementation // Generate a new key @@ -149,7 +156,7 @@ public: /** Increment the next transaction order id @return next transaction order id */ - int64 IncOrderPosNext(); + int64 IncOrderPosNext(CWalletDB *pwalletdb = NULL); typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; typedef std::multimap<int64, TxPair > TxItems; @@ -375,10 +382,12 @@ public: // memory only mutable bool fDebitCached; mutable bool fCreditCached; + mutable bool fImmatureCreditCached; mutable bool fAvailableCreditCached; mutable bool fChangeCached; mutable int64 nDebitCached; mutable int64 nCreditCached; + mutable int64 nImmatureCreditCached; mutable int64 nAvailableCreditCached; mutable int64 nChangeCached; @@ -416,10 +425,12 @@ public: vfSpent.clear(); fDebitCached = false; fCreditCached = false; + fImmatureCreditCached = false; fAvailableCreditCached = false; fChangeCached = false; nDebitCached = 0; nCreditCached = 0; + nImmatureCreditCached = 0; nAvailableCreditCached = 0; nChangeCached = 0; nOrderPos = -1; @@ -563,6 +574,20 @@ public: return nCreditCached; } + int64 GetImmatureCredit(bool fUseCache=true) const + { + if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) + { + if (fUseCache && fImmatureCreditCached) + return nImmatureCreditCached; + nImmatureCreditCached = pwallet->GetCredit(*this); + fImmatureCreditCached = true; + return nImmatureCreditCached; + } + + return 0; + } + int64 GetAvailableCredit(bool fUseCache=true) const { // Must wait until coinbase is safely deep enough in the chain before valuing it |