diff options
37 files changed, 1400 insertions, 648 deletions
@@ -1,9 +1,9 @@ Building Bitcoin -See doc/readme-qt.rst for instructions on building Bitcoin-Qt, +See doc/readme-qt.md for instructions on building Bitcoin-Qt, the intended-for-end-users, nice-graphical-interface, reference implementation of Bitcoin. -See doc/build-*.txt for instructions on building bitcoind, +See doc/build-*.md for instructions on building bitcoind, the intended-for-services, no-graphical-interface, reference implementation of Bitcoin.
\ No newline at end of file diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 1d62941e68..e2dab18abf 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -214,7 +214,8 @@ HEADERS += src/qt/bitcoingui.h \ src/leveldb.h \ src/threadsafety.h \ src/limitedmap.h \ - src/qt/splashscreen.h + src/qt/splashscreen.h \ + src/qt/intro.h SOURCES += src/qt/bitcoin.cpp \ src/qt/bitcoingui.cpp \ @@ -284,7 +285,8 @@ SOURCES += src/qt/bitcoin.cpp \ src/noui.cpp \ src/leveldb.cpp \ src/txdb.cpp \ - src/qt/splashscreen.cpp + src/qt/splashscreen.cpp \ + src/qt/intro.cpp RESOURCES += src/qt/bitcoin.qrc @@ -298,7 +300,8 @@ FORMS += src/qt/forms/sendcoinsdialog.ui \ src/qt/forms/sendcoinsentry.ui \ src/qt/forms/askpassphrasedialog.ui \ src/qt/forms/rpcconsole.ui \ - src/qt/forms/optionsdialog.ui + src/qt/forms/optionsdialog.ui \ + src/qt/forms/intro.ui contains(USE_QRCODE, 1) { HEADERS += src/qt/qrcodedialog.h @@ -339,7 +342,6 @@ QMAKE_EXTRA_COMPILERS += TSQM # "Other files" to show in Qt Creator OTHER_FILES += README.md \ - doc/*.rst \ doc/*.txt \ doc/*.md \ src/bitcoind.cpp \ diff --git a/contrib/debian/README b/contrib/debian/README new file mode 100644 index 0000000000..1cb9b75fbd --- /dev/null +++ b/contrib/debian/README @@ -0,0 +1,20 @@ +This directory contains files used to package bitcoind/bitcoin-qt +for Debian-based Linux systems. + +If you compile bitcoind/bitcoin-qt yourself, there are some +useful files here: + +bitcoin: URI support +-------------------- + +bitcoin-qt.desktop (Gnome / Open Desktop) +To install: + sudo desktop-file-install bitcoin-qt.desktop + sudo update-desktop-database + +If you build yourself, you will either need to modify the paths in +the .desktop file or copy or symlink your bitcoin-qt binary to /usr/bin +and the ../../share/pixmaps/bitcoin128.png to /usr/share/pixmaps + +bitcoin-qt.protocol (KDE) + diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop index 5d6f781e4e..b2a2cef622 100644 --- a/contrib/debian/bitcoin-qt.desktop +++ b/contrib/debian/bitcoin-qt.desktop @@ -4,7 +4,7 @@ Name=Bitcoin Comment=Bitcoin P2P Cryptocurrency Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi -Exec=/usr/bin/bitcoin-qt +Exec=/usr/bin/bitcoin-qt %u Terminal=false Type=Application Icon=/usr/share/pixmaps/bitcoin128.png diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config index aef614d0ca..8340a5dd24 100644 --- a/contrib/gitian-downloader/linux-download-config +++ b/contrib/gitian-downloader/linux-download-config @@ -35,4 +35,8 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami minimum_weight: 120 diff --git a/contrib/gitian-downloader/win32-download-config b/contrib/gitian-downloader/win32-download-config index 0f7032e643..49d52851b6 100644 --- a/contrib/gitian-downloader/win32-download-config +++ b/contrib/gitian-downloader/win32-download-config @@ -35,4 +35,8 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami minimum_weight: 120 diff --git a/contrib/gitian-downloader/wtogami-key.pgp b/contrib/gitian-downloader/wtogami-key.pgp new file mode 100644 index 0000000000..e0f6c4c5fd --- /dev/null +++ b/contrib/gitian-downloader/wtogami-key.pgp @@ -0,0 +1,131 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +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 +=icdI +-----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/build-msw.md b/doc/build-msw.md index 6976c6a560..d348ad7cc3 100644 --- a/doc/build-msw.md +++ b/doc/build-msw.md @@ -1,7 +1,7 @@ WINDOWS BUILD NOTES =================== -See [readme-qt.rst](readme-qt.rst) for instructions on building Bitcoin-Qt, the +See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the graphical user interface. Compilers Supported diff --git a/doc/build-osx.md b/doc/build-osx.md index 6f50cf9457..271f8f55bd 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -5,7 +5,7 @@ This guide will show you how to build bitcoind(headless client) for OSX. Notes ----- -* See [readme-qt.rst](readme-qt.rst) for instructions on building Bitcoin-Qt, the +* See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the graphical user interface. * Tested on OS X 10.5 through 10.8 on Intel processors only. PPC is not supported because it is big-endian. diff --git a/doc/build-unix.md b/doc/build-unix.md index b22df91f0b..4653bba495 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -8,7 +8,7 @@ To Build cd src/ make -f makefile.unix # Headless bitcoin -See readme-qt.rst for instructions on building Bitcoin-Qt, the graphical user interface. +See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the graphical user interface. Dependencies --------------------- diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst deleted file mode 100644 index 95cb33650f..0000000000 --- a/doc/readme-qt.rst +++ /dev/null @@ -1,163 +0,0 @@ -Bitcoin-Qt: Qt4 GUI for Bitcoin -=============================== - -Build instructions -=================== - -Debian -------- - -First, make sure that the required packages for Qt4 development of your -distribution are installed, these are - -:: - -for Debian and Ubuntu <= 11.10 : - -:: - - 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 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 - -For Qt 5 you need the following, otherwise you get an error with lrelease when running qmake: - -:: - - apt-get install qt5-qmake libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev-tools - -then execute the following: - -:: - - qmake - make - -Alternatively, install `Qt Creator`_ and open the `bitcoin-qt.pro` file. - -An executable named `bitcoin-qt` will be built. - -.. _`Qt Creator`: http://qt-project.org/downloads/ - -Mac OS X --------- - -- Download and install the `Qt Mac OS X SDK`_. It is recommended to also install Apple's Xcode with UNIX tools. - -- Download and install either `MacPorts`_ or `HomeBrew`_. - -- Execute the following commands in a terminal to get the dependencies using MacPorts: - -:: - - sudo port selfupdate - sudo port install boost db48 miniupnpc - -- Execute the following commands in a terminal to get the dependencies using HomeBrew: - -:: - - brew update - brew install boost miniupnpc openssl berkeley-db4 - -- If using HomeBrew, edit `bitcoin-qt.pro` to account for library location differences. There's a diff in `contrib/homebrew/bitcoin-qt-pro.patch` that shows what you need to change, or you can just patch by doing - - patch -p1 < contrib/homebrew/bitcoin.qt.pro.patch - -- Open the bitcoin-qt.pro file in Qt Creator and build as normal (cmd-B) - -.. _`Qt Mac OS X SDK`: http://qt-project.org/downloads/ -.. _`MacPorts`: http://www.macports.org/install.php -.. _`HomeBrew`: http://mxcl.github.io/homebrew/ - - -Build configuration options -============================ - -UPnP port forwarding ---------------------- - -To use UPnP for port forwarding behind a NAT router (recommended, as more connections overall allow for a faster and more stable bitcoin experience), pass the following argument to qmake: - -:: - - qmake "USE_UPNP=1" - -(in **Qt Creator**, you can find the setting for additional qmake arguments under "Projects" -> "Build Settings" -> "Build Steps", then click "Details" next to **qmake**) - -This requires miniupnpc for UPnP port mapping. It can be downloaded from -http://miniupnp.tuxfamily.org/files/. UPnP support is not compiled in by default. - -Set USE_UPNP to a different value to control this: - -+------------+--------------------------------------------------------------------------+ -| USE_UPNP=- | no UPnP support, miniupnpc not required; | -+------------+--------------------------------------------------------------------------+ -| USE_UPNP=0 | (the default) built with UPnP, support turned off by default at runtime; | -+------------+--------------------------------------------------------------------------+ -| USE_UPNP=1 | build with UPnP support turned on by default at runtime. | -+------------+--------------------------------------------------------------------------+ - -Notification support for recent (k)ubuntu versions ---------------------------------------------------- - -To see desktop notifications on (k)ubuntu versions starting from 10.04, enable usage of the -FreeDesktop notification interface through DBUS using the following qmake option: - -:: - - qmake "USE_DBUS=1" - -Generation of QR codes ------------------------ - -libqrencode may be used to generate QRCode images for payment requests. -It can be downloaded from http://fukuchi.org/works/qrencode/index.html.en, or installed via your package manager. Pass the USE_QRCODE -flag to qmake to control this: - -+--------------+--------------------------------------------------------------------------+ -| USE_QRCODE=0 | (the default) No QRCode support - libarcode not required | -+--------------+--------------------------------------------------------------------------+ -| USE_QRCODE=1 | QRCode support enabled | -+--------------+--------------------------------------------------------------------------+ - - -Berkely DB version warning -========================== - -A warning for people using the *static binary* version of Bitcoin on a Linux/UNIX-ish system (tl;dr: **Berkely DB databases are not forward compatible**). - -The static binary version of Bitcoin is linked against libdb4.8 (see also `this Debian issue`_). - -Now the nasty thing is that databases from 5.X are not compatible with 4.X. - -If the globally installed development package of Berkely DB installed on your system is 5.X, any source you -build yourself will be linked against that. The first time you run with a 5.X version the database will be upgraded, -and 4.X cannot open the new format. This means that you cannot go back to the old statically linked version without -significant hassle! - -.. _`this Debian issue`: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621425 - -Ubuntu 11.10 warning -==================== - -Ubuntu 11.10 has a package called 'qt-at-spi' installed by default. At the time of writing, having that package -installed causes bitcoin-qt to crash intermittently. The issue has been reported as `launchpad bug 857790`_, but -isn't yet fixed. - -Until the bug is fixed, you can remove the qt-at-spi package to work around the problem, though this will presumably -disable screen reader functionality for Qt apps: - -:: - - sudo apt-get remove qt-at-spi - -.. _`launchpad bug 857790`: https://bugs.launchpad.net/ubuntu/+source/qt-at-spi/+bug/857790 diff --git a/doc/release-process.md b/doc/release-process.md index dc2101e1c1..7b0a73a81e 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -31,7 +31,7 @@ Release Process export SIGNER=(your gitian key, ie bluematt, sipa, etc) export VERSION=(new version, e.g. 0.8.0) - cd ./gitian-builder + pushd ./gitian-builder Fetch and build inputs: (first time, or when dependency versions change) @@ -58,13 +58,14 @@ Release Process ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml pushd build/out zip -r bitcoin-${VERSION}-linux-gitian.zip * - mv bitcoin-${VERSION}-linux-gitian.zip ../../ + mv bitcoin-${VERSION}-linux-gitian.zip ../../../ popd ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml pushd build/out zip -r bitcoin-${VERSION}-win32-gitian.zip * - mv bitcoin-${VERSION}-win32-gitian.zip ../../ + mv bitcoin-${VERSION}-win32-gitian.zip ../../../ + popd popd Build output expected: diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 5908126200..11fac42213 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -195,6 +195,7 @@ static const CRPCCommand vRPCCommands[] = { "help", &help, true, true }, { "stop", &stop, true, true }, { "getblockcount", &getblockcount, true, false }, + { "getbestblockhash", &getbestblockhash, true, false }, { "getconnectioncount", &getconnectioncount, true, false }, { "getpeerinfo", &getpeerinfo, true, false }, { "addnode", &addnode, true, true }, diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 247c47adf9..4d5599be84 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -201,6 +201,7 @@ extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, b extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp +extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); diff --git a/src/core.cpp b/src/core.cpp index b12c90efe8..afba0959cf 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -4,4 +4,298 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "core.h" +#include "util.h" +std::string COutPoint::ToString() const +{ + return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); +} + +void COutPoint::print() const +{ + printf("%s\n", ToString().c_str()); +} + +CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn) +{ + prevout = prevoutIn; + scriptSig = scriptSigIn; + nSequence = nSequenceIn; +} + +CTxIn::CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn, unsigned int nSequenceIn) +{ + prevout = COutPoint(hashPrevTx, nOut); + scriptSig = scriptSigIn; + nSequence = nSequenceIn; +} + +std::string CTxIn::ToString() const +{ + std::string str; + str += "CTxIn("; + str += prevout.ToString(); + if (prevout.IsNull()) + str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); + else + str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); + if (nSequence != std::numeric_limits<unsigned int>::max()) + str += strprintf(", nSequence=%u", nSequence); + str += ")"; + return str; +} + +void CTxIn::print() const +{ + printf("%s\n", ToString().c_str()); +} + +CTxOut::CTxOut(int64 nValueIn, CScript scriptPubKeyIn) +{ + nValue = nValueIn; + scriptPubKey = scriptPubKeyIn; +} + +uint256 CTxOut::GetHash() const +{ + return SerializeHash(*this); +} + +std::string CTxOut::ToString() const +{ + if (scriptPubKey.size() < 6) + return "CTxOut(error)"; + return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); +} + +void CTxOut::print() const +{ + printf("%s\n", ToString().c_str()); +} + +uint256 CTransaction::GetHash() const +{ + return SerializeHash(*this); +} + +bool CTransaction::IsNewerThan(const CTransaction& old) const +{ + if (vin.size() != old.vin.size()) + return false; + for (unsigned int i = 0; i < vin.size(); i++) + if (vin[i].prevout != old.vin[i].prevout) + return false; + + bool fNewer = false; + unsigned int nLowest = std::numeric_limits<unsigned int>::max(); + for (unsigned int i = 0; i < vin.size(); i++) + { + if (vin[i].nSequence != old.vin[i].nSequence) + { + if (vin[i].nSequence <= nLowest) + { + fNewer = false; + nLowest = vin[i].nSequence; + } + if (old.vin[i].nSequence < nLowest) + { + fNewer = true; + nLowest = old.vin[i].nSequence; + } + } + } + return fNewer; +} + +std::string CTransaction::ToString() const +{ + std::string str; + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", + GetHash().ToString().substr(0,10).c_str(), + nVersion, + vin.size(), + vout.size(), + nLockTime); + for (unsigned int i = 0; i < vin.size(); i++) + str += " " + vin[i].ToString() + "\n"; + for (unsigned int i = 0; i < vout.size(); i++) + str += " " + vout[i].ToString() + "\n"; + return str; +} + +void CTransaction::print() const +{ + printf("%s", ToString().c_str()); +} + +// Amount compression: +// * If the amount is 0, output 0 +// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) +// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) +// * call the result n +// * output 1 + 10*(9*n + d - 1) + e +// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 +// (this is decodable, as d is in [1-9] and e is in [0-9]) + +uint64 CTxOutCompressor::CompressAmount(uint64 n) +{ + if (n == 0) + return 0; + int e = 0; + while (((n % 10) == 0) && e < 9) { + n /= 10; + e++; + } + if (e < 9) { + int d = (n % 10); + assert(d >= 1 && d <= 9); + n /= 10; + return 1 + (n*9 + d - 1)*10 + e; + } else { + return 1 + (n - 1)*10 + 9; + } +} + +uint64 CTxOutCompressor::DecompressAmount(uint64 x) +{ + // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 + if (x == 0) + return 0; + x--; + // x = 10*(9*n + d - 1) + e + int e = x % 10; + x /= 10; + uint64 n = 0; + if (e < 9) { + // x = 9*n + d - 1 + int d = (x % 9) + 1; + x /= 9; + // x = n + n = x*10 + d; + } else { + n = x+1; + } + while (e) { + n *= 10; + e--; + } + return n; +} + +// calculate number of bytes for the bitmask, and its number of non-zero bytes +// each bit in the bitmask represents the availability of one output, but the +// availabilities of the first two outputs are encoded separately +void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { + unsigned int nLastUsedByte = 0; + for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { + bool fZero = true; + for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { + if (!vout[2+b*8+i].IsNull()) { + fZero = false; + continue; + } + } + if (!fZero) { + nLastUsedByte = b + 1; + nNonzeroBytes++; + } + } + nBytes += nLastUsedByte; +} + +bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) { + if (out.n >= vout.size()) + return false; + if (vout[out.n].IsNull()) + return false; + undo = CTxInUndo(vout[out.n]); + vout[out.n].SetNull(); + Cleanup(); + if (vout.size() == 0) { + undo.nHeight = nHeight; + undo.fCoinBase = fCoinBase; + undo.nVersion = this->nVersion; + } + return true; +} + +bool CCoins::Spend(int nPos) { + CTxInUndo undo; + COutPoint out(0, nPos); + return Spend(out, undo); +} + +uint256 CBlockHeader::GetHash() const +{ + return Hash(BEGIN(nVersion), END(nNonce)); +} + +uint256 CBlock::BuildMerkleTree() const +{ + vMerkleTree.clear(); + BOOST_FOREACH(const CTransaction& tx, vtx) + vMerkleTree.push_back(tx.GetHash()); + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i+1, nSize-1); + vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), + BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); + } + j += nSize; + } + return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); +} + +std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const +{ + if (vMerkleTree.empty()) + BuildMerkleTree(); + std::vector<uint256> vMerkleBranch; + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; +} + +uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex) +{ + if (nIndex == -1) + return 0; + BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + { + if (nIndex & 1) + hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + else + hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + nIndex >>= 1; + } + return hash; +} + +void CBlock::print() const +{ + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + GetHash().ToString().c_str(), + nVersion, + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), + nTime, nBits, nNonce, + vtx.size()); + for (unsigned int i = 0; i < vtx.size(); i++) + { + printf(" "); + vtx[i].print(); + } + printf(" vMerkleTree: "); + for (unsigned int i = 0; i < vMerkleTree.size(); i++) + printf("%s ", vMerkleTree[i].ToString().c_str()); + printf("\n"); +} diff --git a/src/core.h b/src/core.h index fce9ccc162..1b9d4dd765 100644 --- a/src/core.h +++ b/src/core.h @@ -7,7 +7,6 @@ #include "uint256.h" #include "serialize.h" -#include "util.h" #include "script.h" #include <stdio.h> @@ -42,15 +41,8 @@ public: return !(a == b); } - std::string ToString() const - { - return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); - } - - void print() const - { - printf("%s\n", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -82,19 +74,8 @@ public: nSequence = std::numeric_limits<unsigned int>::max(); } - explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()) - { - prevout = prevoutIn; - scriptSig = scriptSigIn; - nSequence = nSequenceIn; - } - - CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()) - { - prevout = COutPoint(hashPrevTx, nOut); - scriptSig = scriptSigIn; - nSequence = nSequenceIn; - } + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()); + CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()); IMPLEMENT_SERIALIZE ( @@ -120,25 +101,8 @@ public: return !(a == b); } - std::string ToString() const - { - std::string str; - str += "CTxIn("; - str += prevout.ToString(); - if (prevout.IsNull()) - str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); - else - str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); - if (nSequence != std::numeric_limits<unsigned int>::max()) - str += strprintf(", nSequence=%u", nSequence); - str += ")"; - return str; - } - - void print() const - { - printf("%s\n", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; @@ -158,11 +122,7 @@ public: SetNull(); } - CTxOut(int64 nValueIn, CScript scriptPubKeyIn) - { - nValue = nValueIn; - scriptPubKey = scriptPubKeyIn; - } + CTxOut(int64 nValueIn, CScript scriptPubKeyIn); IMPLEMENT_SERIALIZE ( @@ -181,10 +141,7 @@ public: return (nValue == -1); } - uint256 GetHash() const - { - return SerializeHash(*this); - } + uint256 GetHash() const; bool IsDust(int64 nMinRelayTxFee) const { @@ -210,17 +167,8 @@ public: return !(a == b); } - std::string ToString() const - { - if (scriptPubKey.size() < 6) - return "CTxOut(error)"; - return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); - } - - void print() const - { - printf("%s\n", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; @@ -265,39 +213,8 @@ public: return (vin.empty() && vout.empty()); } - uint256 GetHash() const - { - return SerializeHash(*this); - } - - bool IsNewerThan(const CTransaction& old) const - { - if (vin.size() != old.vin.size()) - return false; - for (unsigned int i = 0; i < vin.size(); i++) - if (vin[i].prevout != old.vin[i].prevout) - return false; - - bool fNewer = false; - unsigned int nLowest = std::numeric_limits<unsigned int>::max(); - for (unsigned int i = 0; i < vin.size(); i++) - { - if (vin[i].nSequence != old.vin[i].nSequence) - { - if (vin[i].nSequence <= nLowest) - { - fNewer = false; - nLowest = vin[i].nSequence; - } - if (old.vin[i].nSequence < nLowest) - { - fNewer = true; - nLowest = old.vin[i].nSequence; - } - } - } - return fNewer; - } + uint256 GetHash() const; + bool IsNewerThan(const CTransaction& old) const; bool IsCoinBase() const { @@ -318,26 +235,8 @@ public: } - std::string ToString() const - { - std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", - GetHash().ToString().substr(0,10).c_str(), - nVersion, - vin.size(), - vout.size(), - nLockTime); - for (unsigned int i = 0; i < vin.size(); i++) - str += " " + vin[i].ToString() + "\n"; - for (unsigned int i = 0; i < vout.size(); i++) - str += " " + vout[i].ToString() + "\n"; - return str; - } - - void print() const - { - printf("%s", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; /** wrapper for CTxOut that provides a more compact serialization */ @@ -521,26 +420,7 @@ public: return !(a == b); } - // calculate number of bytes for the bitmask, and its number of non-zero bytes - // each bit in the bitmask represents the availability of one output, but the - // availabilities of the first two outputs are encoded separately - void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { - unsigned int nLastUsedByte = 0; - for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { - bool fZero = true; - for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { - if (!vout[2+b*8+i].IsNull()) { - fZero = false; - continue; - } - } - if (!fZero) { - nLastUsedByte = b + 1; - nNonzeroBytes++; - } - } - nBytes += nLastUsedByte; - } + void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const; bool IsCoinBase() const { return fCoinBase; @@ -633,28 +513,10 @@ public: } // mark an outpoint spent, and construct undo information - bool Spend(const COutPoint &out, CTxInUndo &undo) { - if (out.n >= vout.size()) - return false; - if (vout[out.n].IsNull()) - return false; - undo = CTxInUndo(vout[out.n]); - vout[out.n].SetNull(); - Cleanup(); - if (vout.size() == 0) { - undo.nHeight = nHeight; - undo.fCoinBase = fCoinBase; - undo.nVersion = this->nVersion; - } - return true; - } + bool Spend(const COutPoint &out, CTxInUndo &undo); // mark a vout spent - bool Spend(int nPos) { - CTxInUndo undo; - COutPoint out(0, nPos); - return Spend(out, undo); - } + bool Spend(int nPos); // check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { @@ -722,10 +584,7 @@ public: return (nBits == 0); } - uint256 GetHash() const - { - return Hash(BEGIN(nVersion), END(nNonce)); - } + uint256 GetHash() const; int64 GetBlockTime() const { @@ -779,24 +638,7 @@ public: return block; } - uint256 BuildMerkleTree() const - { - vMerkleTree.clear(); - BOOST_FOREACH(const CTransaction& tx, vtx) - vMerkleTree.push_back(tx.GetHash()); - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - for (int i = 0; i < nSize; i += 2) - { - int i2 = std::min(i+1, nSize-1); - vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), - BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); - } - j += nSize; - } - return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); - } + uint256 BuildMerkleTree() const; const uint256 &GetTxHash(unsigned int nIndex) const { assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first @@ -804,56 +646,9 @@ public: return vMerkleTree[nIndex]; } - std::vector<uint256> GetMerkleBranch(int nIndex) const - { - if (vMerkleTree.empty()) - BuildMerkleTree(); - std::vector<uint256> vMerkleBranch; - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - int i = std::min(nIndex^1, nSize-1); - vMerkleBranch.push_back(vMerkleTree[j+i]); - nIndex >>= 1; - j += nSize; - } - return vMerkleBranch; - } - - static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex) - { - if (nIndex == -1) - return 0; - BOOST_FOREACH(const uint256& otherside, vMerkleBranch) - { - if (nIndex & 1) - hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); - else - hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); - nIndex >>= 1; - } - return hash; - } - - void print() const - { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", - GetHash().ToString().c_str(), - nVersion, - hashPrevBlock.ToString().c_str(), - hashMerkleRoot.ToString().c_str(), - nTime, nBits, nNonce, - vtx.size()); - for (unsigned int i = 0; i < vtx.size(); i++) - { - printf(" "); - vtx[i].print(); - } - printf(" vMerkleTree: "); - for (unsigned int i = 0; i < vMerkleTree.size(); i++) - printf("%s ", vMerkleTree[i].ToString().c_str()); - printf("\n"); - } + std::vector<uint256> GetMerkleBranch(int nIndex) const; + static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex); + void print() const; }; #endif diff --git a/src/db.cpp b/src/db.cpp index 93f3f5d8c4..03f46f3c26 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -8,7 +8,6 @@ #include "util.h" #include "hash.h" #include "addrman.h" -#include <boost/version.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <openssl/rand.h> diff --git a/src/init.cpp b/src/init.cpp index 44477081be..c5a8cc9fbe 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -119,7 +119,7 @@ void Shutdown() } bitdb.Flush(true); boost::filesystem::remove(GetPidFile()); - UnregisterWallet(pwalletMain); + UnregisterAllWallets(); delete pwalletMain; } @@ -237,12 +237,12 @@ std::string HelpMessage() strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + "\n"; strUsage += " -par=<n> " + _("Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)") + "\n"; - strUsage += "\n"; _("Block creation options:") + "\n"; + strUsage += "\n" + _("Block creation options:") + "\n"; strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n"; strUsage += " -blockmaxsize=<n> " + _("Set maximum block size in bytes (default: 250000)") + "\n"; strUsage += " -blockprioritysize=<n> " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n"; - strUsage += "\n"; _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n"; + strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n"; strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n"; strUsage += " -rpcsslcertificatechainfile=<file.cert> " + _("Server certificate file (default: server.cert)") + "\n"; strUsage += " -rpcsslprivatekeyfile=<file.pem> " + _("Server private key (default: server.pem)") + "\n"; diff --git a/src/key.cpp b/src/key.cpp index f73708199a..1ab4c62ebf 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -155,7 +155,8 @@ public: BN_clear_free(&bn); } - void GetPrivKey(CPrivKey &privkey) { + void GetPrivKey(CPrivKey &privkey, bool fCompressed) { + EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); int nSize = i2d_ECPrivateKey(pkey, NULL); assert(nSize); privkey.resize(nSize); @@ -304,7 +305,7 @@ CPrivKey CKey::GetPrivKey() const { CECKey key; key.SetSecretBytes(vch); CPrivKey privkey; - key.GetPrivKey(privkey); + key.GetPrivKey(privkey, fCompressed); return privkey; } diff --git a/src/main.cpp b/src/main.cpp index f3ce436606..d358914406 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -99,9 +99,16 @@ void UnregisterWallet(CWallet* pwalletIn) } } +void UnregisterAllWallets() +{ + LOCK(cs_setpwalletRegistered); + setpwalletRegistered.clear(); +} + // get the wallet transaction with the given hash (if it exists) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) if (pwallet->GetTransaction(hashTx,wtx)) return true; @@ -111,6 +118,7 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) // erases transaction with the given hash from all wallets void static EraseFromWallets(uint256 hash) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->EraseFromWallet(hash); } @@ -118,6 +126,7 @@ void static EraseFromWallets(uint256 hash) // make sure all wallets know about the given transaction, in the given block void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate); } @@ -125,6 +134,7 @@ void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* // notify wallets about a new best chain void static SetBestChain(const CBlockLocator& loc) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->SetBestChain(loc); } @@ -132,6 +142,7 @@ void static SetBestChain(const CBlockLocator& loc) // notify wallets about an updated transaction void static UpdatedTransaction(const uint256& hashTx) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->UpdatedTransaction(hashTx); } @@ -139,6 +150,7 @@ void static UpdatedTransaction(const uint256& hashTx) // dump all wallets void static PrintWallets(const CBlock& block) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->PrintWallet(block); } @@ -146,6 +158,7 @@ void static PrintWallets(const CBlock& block) // notify wallets about an incoming inventory (for request counts) void static Inventory(const uint256& hash) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->Inventory(hash); } @@ -153,6 +166,7 @@ void static Inventory(const uint256& hash) // ask wallets to resend their transactions void static ResendWalletTransactions() { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->ResendWalletTransactions(); } @@ -457,38 +471,53 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) -bool IsStandardTx(const CTransaction& tx) +bool IsStandardTx(const CTransaction& tx, string& reason) { - if (tx.nVersion > CTransaction::CURRENT_VERSION) + if (tx.nVersion > CTransaction::CURRENT_VERSION) { + reason = "version"; return false; + } - if (!IsFinalTx(tx)) + if (!IsFinalTx(tx)) { + reason = "non-final"; return false; + } // Extremely large transactions with lots of inputs can cost the network // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); - if (sz >= MAX_STANDARD_TX_SIZE) + if (sz >= MAX_STANDARD_TX_SIZE) { + reason = "tx-size"; return false; + } BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG // pay-to-script-hash, which is 3 ~80-byte signatures, 3 // ~65-byte public keys, plus a few script ops. - if (txin.scriptSig.size() > 500) + if (txin.scriptSig.size() > 500) { + reason = "scriptsig-size"; return false; - if (!txin.scriptSig.IsPushOnly()) + } + if (!txin.scriptSig.IsPushOnly()) { + reason = "scriptsig-not-pushonly"; return false; + } } BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (!::IsStandard(txout.scriptPubKey)) + if (!::IsStandard(txout.scriptPubKey)) { + reason = "scriptpubkey"; return false; - if (txout.IsDust(CTransaction::nMinRelayTxFee)) + } + if (txout.IsDust(CTransaction::nMinRelayTxFee)) { + reason = "dust"; return false; + } } + return true; } @@ -782,8 +811,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); // Rather not work on nonstandard transactions (unless -testnet) - if (!TestNet() && !IsStandardTx(tx)) - return error("CTxMemPool::accept() : nonstandard transaction type"); + string reason; + if (!TestNet() && !IsStandardTx(tx, reason)) + return error("CTxMemPool::accept() : nonstandard transaction: %s", + reason.c_str()); // is it already in the memory pool? uint256 hash = tx.GetHash(); @@ -4747,59 +4778,6 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); } -// Amount compression: -// * If the amount is 0, output 0 -// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) -// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) -// * call the result n -// * output 1 + 10*(9*n + d - 1) + e -// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 -// (this is decodable, as d is in [1-9] and e is in [0-9]) - -uint64 CTxOutCompressor::CompressAmount(uint64 n) -{ - if (n == 0) - return 0; - int e = 0; - while (((n % 10) == 0) && e < 9) { - n /= 10; - e++; - } - if (e < 9) { - int d = (n % 10); - assert(d >= 1 && d <= 9); - n /= 10; - return 1 + (n*9 + d - 1)*10 + e; - } else { - return 1 + (n - 1)*10 + 9; - } -} - -uint64 CTxOutCompressor::DecompressAmount(uint64 x) -{ - // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 - if (x == 0) - return 0; - x--; - // x = 10*(9*n + d - 1) + e - int e = x % 10; - x /= 10; - uint64 n = 0; - if (e < 9) { - // x = 9*n + d - 1 - int d = (x % 9) + 1; - x /= 9; - // x = n - n = x*10 + d; - } else { - n = x+1; - } - while (e) { - n *= 10; - e--; - } - return n; -} class CMainCleanup diff --git a/src/main.h b/src/main.h index 9e0235fa57..8ad2437c63 100644 --- a/src/main.h +++ b/src/main.h @@ -119,6 +119,8 @@ struct CBlockTemplate; void RegisterWallet(CWallet* pwalletIn); /** Unregister a wallet from core */ void UnregisterWallet(CWallet* pwalletIn); +/** Unregister all wallets from core */ +void UnregisterAllWallets(); /** Push an updated transaction to all registered wallets */ void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); @@ -324,7 +326,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state); /** Check for standard transaction types @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx); +bool IsStandardTx(const CTransaction& tx, std::string& reason); bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0); diff --git a/src/makefile.mingw b/src/makefile.mingw index 3659f52040..002e36d3e2 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -21,7 +21,7 @@ USE_UPNP:=- USE_IPV6:=1 DEPSDIR?=/usr/local -BOOST_SUFFIX?=-mgw46-mt-sd-1_52 +BOOST_SUFFIX?=-mgw46-mt-s-1_52 INCLUDEPATHS= \ -I"$(CURDIR)" \ diff --git a/src/net.cpp b/src/net.cpp index 5418c3de40..bd9aa1f50f 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1598,8 +1598,12 @@ bool BindListenPort(const CService &addrBind, string& strError) // and enable it by default or not. Try to enable it, if possible. if (addrBind.IsIPv6()) { #ifdef IPV6_V6ONLY +#ifdef WIN32 + setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int)); +#else setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int)); #endif +#endif #ifdef WIN32 int nProtLevel = 10 /* PROTECTION_LEVEL_UNRESTRICTED */; int nParameterId = 23 /* IPV6_PROTECTION_LEVEl */; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 76e88b36a7..b0c45d6863 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -15,6 +15,7 @@ #include "ui_interface.h" #include "paymentserver.h" #include "splashscreen.h" +#include "intro.h" #include <QMessageBox> #if QT_VERSION < 0x050000 @@ -24,6 +25,7 @@ #include <QTimer> #include <QTranslator> #include <QLibraryInfo> +#include <QSettings> #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) #define _BITCOIN_QT_PLUGINS_INCLUDED @@ -110,6 +112,46 @@ static void handleRunawayException(std::exception *e) exit(1); } +/** Set up translations */ +static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator) +{ + QSettings settings; + + // Get desired locale (e.g. "de_DE") + // 1) System default language + QString lang_territory = QLocale::system().name(); + // 2) Language from QSettings + QString lang_territory_qsettings = settings.value("language", "").toString(); + if(!lang_territory_qsettings.isEmpty()) + lang_territory = lang_territory_qsettings; + // 3) -lang command line argument + lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString())); + + // Convert to "de" only by truncating "_DE" + QString lang = lang_territory; + lang.truncate(lang_territory.lastIndexOf('_')); + + // Load language files for configured locale: + // - First load the translator for the base language, without territory + // - Then load the more specific locale translator + + // Load e.g. qt_de.qm + if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + QApplication::installTranslator(&qtTranslatorBase); + + // Load e.g. qt_de_DE.qm + if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + QApplication::installTranslator(&qtTranslator); + + // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc) + if (translatorBase.load(lang, ":/translations/")) + QApplication::installTranslator(&translatorBase); + + // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc) + if (translator.load(lang_territory, ":/translations/")) + QApplication::installTranslator(&translator); +} + #ifndef BITCOIN_QT_TEST int main(int argc, char *argv[]) { @@ -130,6 +172,22 @@ int main(int argc, char *argv[]) // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType< bool* >(); + // Application identification (must be set before OptionsModel is initialized, + // as it is used to locate QSettings) + QApplication::setOrganizationName("Bitcoin"); + QApplication::setOrganizationDomain("bitcoin.org"); + if (GetBoolArg("-testnet", false)) // Separate UI settings for testnet + QApplication::setApplicationName("Bitcoin-Qt-testnet"); + else + QApplication::setApplicationName("Bitcoin-Qt"); + + // Now that QSettings are accessible, initialize translations + QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; + initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); + + // User language is set up: pick a data directory + Intro::pickDataDirectory(); + // Do this early as we don't want to bother initializing if we are just calling IPC // ... but do it after creating app, so QCoreApplication::arguments is initialized: if (PaymentServer::ipcSendCommandLine()) @@ -142,53 +200,15 @@ int main(int argc, char *argv[]) // ... then bitcoin.conf: if (!boost::filesystem::is_directory(GetDataDir(false))) { - // This message can not be translated, as translation is not initialized yet - // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory) - QMessageBox::critical(0, "Bitcoin", - QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); + QMessageBox::critical(0, QObject::tr("Bitcoin"), + QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); return 1; } ReadConfigFile(mapArgs, mapMultiArgs); - // Application identification (must be set before OptionsModel is initialized, - // as it is used to locate QSettings) - QApplication::setOrganizationName("Bitcoin"); - QApplication::setOrganizationDomain("bitcoin.org"); - if (GetBoolArg("-testnet", false)) // Separate UI settings for testnet - QApplication::setApplicationName("Bitcoin-Qt-testnet"); - else - QApplication::setApplicationName("Bitcoin-Qt"); - // ... then GUI settings: OptionsModel optionsModel; - // Get desired locale (e.g. "de_DE") from command line or use system locale - QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString())); - QString lang = lang_territory; - // Convert to "de" only by truncating "_DE" - lang.truncate(lang_territory.lastIndexOf('_')); - - QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; - // Load language files for configured locale: - // - First load the translator for the base language, without territory - // - Then load the more specific locale translator - - // Load e.g. qt_de.qm - if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) - app.installTranslator(&qtTranslatorBase); - - // Load e.g. qt_de_DE.qm - if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) - app.installTranslator(&qtTranslator); - - // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc) - if (translatorBase.load(lang, ":/translations/")) - app.installTranslator(&translatorBase); - - // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc) - if (translator.load(lang_territory, ":/translations/")) - app.installTranslator(&translator); - // Subscribe to global signals from core uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 1afce2eb7c..cb09e93e76 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -33,6 +33,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot obtain a lock on data directory %s. Bitcoin is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Enter regression test mode, which uses a special chain in which blocks can " +"be solved instantly. This is intended for regression testing tools and app " +"development."), +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."), @@ -133,6 +137,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"), QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 288, 0 = all)"), QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-4, default: 3)"), QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"), +QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Information"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui new file mode 100644 index 0000000000..0f6ae5a7d0 --- /dev/null +++ b/src/qt/forms/intro.ui @@ -0,0 +1,266 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Intro</class> + <widget class="QDialog" name="Intro"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>674</width> + <height>363</height> + </rect> + </property> + <property name="windowTitle"> + <string>Welcome</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label_2"> + <property name="styleSheet"> + <string notr="true">QLabel { font-style:italic; }</string> + </property> + <property name="text"> + <string>Welcome to Bitcoin-Qt.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>15</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>As this is the first time the program is launched, you can choose where Bitcoin-Qt will store its data.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="sizeWarningLabel"> + <property name="text"> + <string>Bitcoin-Qt will download and store a copy of the Bitcoin block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dataDirDefault"> + <property name="text"> + <string>Use the default data directory</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="dataDirCustom"> + <property name="text"> + <string>Use a custom data directory:</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>60</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLineEdit" name="dataDirectory"/> + </item> + <item> + <widget class="QPushButton" name="ellipsisButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string notr="true">…</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>5</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="freeSpace"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>5</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="errorMessage"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Intro</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Intro</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 88a6e7226e..3d1e91efdc 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -500,7 +500,8 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) : uiOptions = tr("UI options") + ":\n" + " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" + " -min " + tr("Start minimized") + "\n" + - " -splash " + tr("Show splash screen on startup (default: 1)") + "\n"; + " -splash " + tr("Show splash screen on startup (default: 1)") + "\n" + + " -choosedatadir " + tr("Choose data directory on startup (default: 0)") + "\n"; setWindowTitle(tr("Bitcoin-Qt")); setTextFormat(Qt::PlainText); diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp new file mode 100644 index 0000000000..51f3c812e4 --- /dev/null +++ b/src/qt/intro.cpp @@ -0,0 +1,270 @@ +#include "intro.h" +#include "ui_intro.h" +#include "util.h" + +#include <QFileDialog> +#include <QSettings> +#include <QMessageBox> + +#include <boost/filesystem.hpp> + +/* Minimum free space (in bytes) needed for data directory */ +static const uint64 GB_BYTES = 1000000000LL; +static const uint64 BLOCK_CHAIN_SIZE = 10LL * GB_BYTES; + +/* Check free space asynchronously to prevent hanging the UI thread. + + Up to one request to check a path is in flight to this thread; when the check() + function runs, the current path is requested from the associated Intro object. + The reply is sent back through a signal. + + This ensures that no queue of checking requests is built up while the user is + still entering the path, and that always the most recently entered path is checked as + soon as the thread becomes available. +*/ +class FreespaceChecker : public QObject +{ + Q_OBJECT +public: + FreespaceChecker(Intro *intro); + + enum Status { + ST_OK, + ST_ERROR + }; + +public slots: + void check(); + +signals: + void reply(int status, const QString &message, quint64 available); + +private: + Intro *intro; +}; + +#include "intro.moc" + +FreespaceChecker::FreespaceChecker(Intro *intro) +{ + this->intro = intro; +} + +void FreespaceChecker::check() +{ + namespace fs = boost::filesystem; + QString dataDirStr = intro->getPathToCheck(); + fs::path dataDir = fs::path(dataDirStr.toStdString()); + uint64 freeBytesAvailable = 0; + int replyStatus = ST_OK; + QString replyMessage = tr("A new data directory will be created."); + + /* Find first parent that exists, so that fs::space does not fail */ + fs::path parentDir = dataDir; + while(parentDir.has_parent_path() && !fs::exists(parentDir)) + { + parentDir = parentDir.parent_path(); + } + + try { + freeBytesAvailable = fs::space(parentDir).available; + if(fs::exists(dataDir)) + { + if(fs::is_directory(dataDir)) + { + QString separator = QDir::toNativeSeparators("/"); + replyStatus = ST_OK; + replyMessage = tr("Directory already exists. Add <code>%1name</code> if you intend to create a new directory here.").arg(separator); + } else { + replyStatus = ST_ERROR; + replyMessage = tr("Path already exists, and is not a directory."); + } + } + } catch(fs::filesystem_error &e) + { + /* Parent directory does not exist or is not accessible */ + replyStatus = ST_ERROR; + replyMessage = tr("Cannot create data directory here."); + } + emit reply(replyStatus, replyMessage, freeBytesAvailable); +} + + +Intro::Intro(QWidget *parent) : + QDialog(parent), + ui(new Ui::Intro), + thread(0), + signalled(false) +{ + ui->setupUi(this); + ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES)); + startThread(); +} + +Intro::~Intro() +{ + delete ui; + /* Ensure thread is finished before it is deleted */ + emit stopThread(); + thread->wait(); +} + +QString Intro::getDataDirectory() +{ + return ui->dataDirectory->text(); +} + +void Intro::setDataDirectory(const QString &dataDir) +{ + ui->dataDirectory->setText(dataDir); + if(dataDir == getDefaultDataDirectory()) + { + ui->dataDirDefault->setChecked(true); + ui->dataDirectory->setEnabled(false); + ui->ellipsisButton->setEnabled(false); + } else { + ui->dataDirCustom->setChecked(true); + ui->dataDirectory->setEnabled(true); + ui->ellipsisButton->setEnabled(true); + } +} + +QString Intro::getDefaultDataDirectory() +{ + return QString::fromStdString(GetDefaultDataDir().string()); +} + +void Intro::pickDataDirectory() +{ + namespace fs = boost::filesystem;; + QSettings settings; + /* If data directory provided on command line, no need to look at settings + or show a picking dialog */ + if(!GetArg("-datadir", "").empty()) + return; + /* 1) Default data directory for operating system */ + QString dataDir = getDefaultDataDirectory(); + /* 2) Allow QSettings to override default dir */ + dataDir = settings.value("strDataDir", dataDir).toString(); + + if(!fs::exists(dataDir.toStdString()) || GetBoolArg("-choosedatadir", false)) + { + /* If current default data directory does not exist, let the user choose one */ + Intro intro; + intro.setDataDirectory(dataDir); + while(true) + { + if(!intro.exec()) + { + /* Cancel clicked */ + exit(0); + } + dataDir = intro.getDataDirectory(); + try { + fs::create_directory(dataDir.toStdString()); + break; + } catch(fs::filesystem_error &e) { + QMessageBox::critical(0, QObject::tr("Bitcoin"), + QObject::tr("Error: Specified data directory \"%1\" can not be created.").arg(dataDir)); + /* fall through, back to choosing screen */ + } + } + + settings.setValue("strDataDir", dataDir); + } + SoftSetArg("-datadir", dataDir.toStdString()); +} + +void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable) +{ + switch(status) + { + case FreespaceChecker::ST_OK: + ui->errorMessage->setText(message); + ui->errorMessage->setStyleSheet(""); + break; + case FreespaceChecker::ST_ERROR: + ui->errorMessage->setText(tr("Error") + ": " + message); + ui->errorMessage->setStyleSheet("QLabel { color: #800000 }"); + break; + } + /* Indicate number of bytes available */ + if(status == FreespaceChecker::ST_ERROR) + { + ui->freeSpace->setText(""); + } else { + QString freeString = QString::number(bytesAvailable/GB_BYTES) + tr("GB of free space available"); + if(bytesAvailable < BLOCK_CHAIN_SIZE) + { + freeString += " " + tr("(of %1GB needed)").arg(BLOCK_CHAIN_SIZE/GB_BYTES); + ui->freeSpace->setStyleSheet("QLabel { color: #800000 }"); + } else { + ui->freeSpace->setStyleSheet(""); + } + ui->freeSpace->setText(freeString+"."); + } + /* Don't allow confirm in ERROR state */ + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR); +} + +void Intro::on_dataDirectory_textChanged(const QString &dataDirStr) +{ + /* Disable OK button until check result comes in */ + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + checkPath(dataDirStr); +} + +void Intro::on_ellipsisButton_clicked() +{ + QString dir = QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text()); + if(!dir.isEmpty()) + ui->dataDirectory->setText(dir); +} + +void Intro::on_dataDirDefault_clicked() +{ + setDataDirectory(getDefaultDataDirectory()); +} + +void Intro::on_dataDirCustom_clicked() +{ + ui->dataDirectory->setEnabled(true); + ui->ellipsisButton->setEnabled(true); +} + +void Intro::startThread() +{ + thread = new QThread(this); + FreespaceChecker *executor = new FreespaceChecker(this); + executor->moveToThread(thread); + + connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64))); + connect(this, SIGNAL(requestCheck()), executor, SLOT(check())); + /* make sure executor object is deleted in its own thread */ + connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater())); + connect(this, SIGNAL(stopThread()), thread, SLOT(quit())); + + thread->start(); +} + +void Intro::checkPath(const QString &dataDir) +{ + mutex.lock(); + pathToCheck = dataDir; + if(!signalled) + { + signalled = true; + emit requestCheck(); + } + mutex.unlock(); +} + +QString Intro::getPathToCheck() +{ + QString retval; + mutex.lock(); + retval = pathToCheck; + signalled = false; /* new request can be queued now */ + mutex.unlock(); + return retval; +} diff --git a/src/qt/intro.h b/src/qt/intro.h new file mode 100644 index 0000000000..b246c65a82 --- /dev/null +++ b/src/qt/intro.h @@ -0,0 +1,67 @@ +#ifndef INTRO_H +#define INTRO_H + +#include <QDialog> +#include <QThread> +#include <QMutex> + +namespace Ui { +class Intro; +} +class FreespaceChecker; + +/** Introduction screen (pre-GUI startup). + Allows the user to choose a data directory, + in which the wallet and block chain will be stored. + */ +class Intro : public QDialog +{ + Q_OBJECT + +public: + explicit Intro(QWidget *parent = 0); + ~Intro(); + + QString getDataDirectory(); + void setDataDirectory(const QString &dataDir); + + /** + * Determine data directory. Let the user choose if the current one doesn't exist. + * + * @note do NOT call global GetDataDir() before calling this function, this + * will cause the wrong path to be cached. + */ + static void pickDataDirectory(); + + /** + * Determine default data directory for operating system. + */ + static QString getDefaultDataDirectory(); +signals: + void requestCheck(); + void stopThread(); + +public slots: + void setStatus(int status, const QString &message, quint64 bytesAvailable); + +private slots: + void on_dataDirectory_textChanged(const QString &arg1); + void on_ellipsisButton_clicked(); + void on_dataDirDefault_clicked(); + void on_dataDirCustom_clicked(); + +private: + Ui::Intro *ui; + QThread *thread; + QMutex mutex; + bool signalled; + QString pathToCheck; + + void startThread(); + void checkPath(const QString &dataDir); + QString getPathToCheck(); + + friend class FreespaceChecker; +}; + +#endif // INTRO_H diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 2006a5296b..7628b39bd3 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -143,7 +143,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Send &Coins</translation> </message> <message> - <location line="+260"/> + <location line="+265"/> <source>Export Address Book Data</source> <translation>Export Address Book Data</translation> </message> @@ -325,17 +325,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="+233"/> + <location filename="../bitcoingui.cpp" line="+257"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+280"/> + <location line="+268"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-349"/> + <location line="-343"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -375,7 +375,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Quit application</translation> </message> <message> - <location line="+4"/> + <location line="+7"/> <source>Show information about Bitcoin</source> <translation>Show information about Bitcoin</translation> </message> @@ -395,7 +395,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Options...</translation> </message> <message> - <location line="+6"/> + <location line="+9"/> <source>&Encrypt Wallet...</source> <translation>&Encrypt Wallet...</translation> </message> @@ -410,7 +410,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Change Passphrase...</translation> </message> <message> - <location line="+285"/> + <location line="+273"/> <source>Importing blocks from disk...</source> <translation>Importing blocks from disk...</translation> </message> @@ -420,17 +420,17 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="-347"/> + <location line="-341"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> <message> - <location line="+49"/> + <location line="+52"/> <source>Modify configuration options for Bitcoin</source> <translation>Modify configuration options for Bitcoin</translation> </message> <message> - <location line="+9"/> + <location line="+12"/> <source>Backup wallet to another location</source> <translation>Backup wallet to another location</translation> </message> @@ -455,18 +455,20 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Verify message...</translation> </message> <message> - <location line="-165"/> + <location line="-183"/> + <location line="+6"/> <location line="+530"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-530"/> + <location line="-536"/> + <location line="+6"/> <source>Wallet</source> <translation>Wallet</translation> </message> <message> - <location line="+101"/> + <location line="+107"/> <source>&Send</source> <translation>&Send</translation> </message> @@ -481,12 +483,14 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Addresses</translation> </message> <message> - <location line="+22"/> + <location line="+23"/> + <location line="+2"/> <source>&About Bitcoin</source> <translation>&About Bitcoin</translation> </message> <message> - <location line="+9"/> + <location line="+10"/> + <location line="+2"/> <source>&Show / Hide</source> <translation>&Show / Hide</translation> </message> @@ -531,18 +535,19 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Tabs toolbar</translation> </message> <message> - <location line="+17"/> - <location line="+10"/> + <location line="-228"/> + <location line="+288"/> <source>[testnet]</source> <translation>[testnet]</translation> </message> <message> - <location line="+47"/> + <location line="-5"/> + <location line="+5"/> <source>Bitcoin client</source> <translation>Bitcoin client</translation> </message> <message numerus="yes"> - <location line="+141"/> + <location line="+143"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -684,7 +689,7 @@ Address: %4 <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+111"/> + <location filename="../bitcoin.cpp" line="+109"/> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> <translation>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</translation> </message> @@ -692,7 +697,7 @@ Address: %4 <context> <name>ClientModel</name> <message> - <location filename="../clientmodel.cpp" line="+104"/> + <location filename="../clientmodel.cpp" line="+105"/> <source>Network Alert</source> <translation>Network Alert</translation> </message> @@ -768,7 +773,7 @@ Address: %4 <context> <name>GUIUtil::HelpMessageBox</name> <message> - <location filename="../guiutil.cpp" line="+424"/> + <location filename="../guiutil.cpp" line="+493"/> <location line="+12"/> <source>Bitcoin-Qt</source> <translation>Bitcoin-Qt</translation> @@ -982,7 +987,7 @@ Address: %4 <translation>&Apply</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+53"/> + <location filename="../optionsdialog.cpp" line="+54"/> <source>default</source> <translation>default</translation> </message> @@ -1028,17 +1033,12 @@ Address: %4 </message> <message> <location line="+50"/> - <location line="+166"/> + <location line="+202"/> <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> </message> <message> - <location line="-124"/> - <source>Balance:</source> - <translation>Balance:</translation> - </message> - <message> - <location line="+29"/> + <location line="-131"/> <source>Unconfirmed:</source> <translation>Unconfirmed:</translation> </message> @@ -1048,7 +1048,22 @@ Address: %4 <translation>Wallet</translation> </message> <message> - <location line="+107"/> + <location line="+49"/> + <source>Confirmed:</source> + <translation>Confirmed:</translation> + </message> + <message> + <location line="+16"/> + <source>Your current spendable balance</source> + <translation>Your current spendable balance</translation> + </message> + <message> + <location line="+29"/> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> + </message> + <message> + <location line="+13"/> <source>Immature:</source> <translation>Immature:</translation> </message> @@ -1058,19 +1073,19 @@ Address: %4 <translation>Mined balance that has not yet matured</translation> </message> <message> - <location line="+46"/> - <source><b>Recent transactions</b></source> - <translation><b>Recent transactions</b></translation> + <location line="+13"/> + <source>Total:</source> + <translation>Total:</translation> </message> <message> - <location line="-101"/> - <source>Your current balance</source> - <translation>Your current balance</translation> + <location line="+16"/> + <source>Your current total balance</source> + <translation>Your current total balance</translation> </message> <message> - <location line="+29"/> - <source>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</source> - <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</translation> + <location line="+53"/> + <source><b>Recent transactions</b></source> + <translation><b>Recent transactions</b></translation> </message> <message> <location filename="../overviewpage.cpp" line="+116"/> @@ -1082,7 +1097,7 @@ Address: %4 <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+107"/> + <location filename="../paymentserver.cpp" line="+109"/> <source>Cannot start bitcoin: click-to-pay handler</source> <translation>Cannot start bitcoin: click-to-pay handler</translation> </message> @@ -1120,7 +1135,7 @@ Address: %4 <translation>&Save As...</translation> </message> <message> - <location filename="../qrcodedialog.cpp" line="+62"/> + <location filename="../qrcodedialog.cpp" line="+64"/> <source>Error encoding URI into QR Code.</source> <translation>Error encoding URI into QR Code.</translation> </message> @@ -1162,7 +1177,7 @@ Address: %4 <location line="+53"/> <location line="+23"/> <location line="+23"/> - <location filename="../rpcconsole.cpp" line="+339"/> + <location filename="../rpcconsole.cpp" line="+343"/> <source>N/A</source> <translation>N/A</translation> </message> @@ -1296,7 +1311,7 @@ Address: %4 <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+124"/> + <location filename="../sendcoinsdialog.cpp" line="+128"/> <location line="+5"/> <location line="+5"/> <location line="+5"/> @@ -1347,12 +1362,13 @@ Address: %4 <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-59"/> + <location filename="../sendcoinsdialog.cpp" line="-62"/> + <location line="+2"/> <source><b>%1</b> to %2 (%3)</source> <translation><b>%1</b> to %2 (%3)</translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>Confirm send coins</source> <translation>Confirm send coins</translation> </message> @@ -1662,7 +1678,7 @@ Address: %4 <context> <name>SplashScreen</name> <message> - <location filename="../splashscreen.cpp" line="+22"/> + <location filename="../splashscreen.cpp" line="+23"/> <source>The Bitcoin developers</source> <translation>The Bitcoin developers</translation> </message> @@ -2096,7 +2112,7 @@ Address: %4 <translation>Show transaction details</translation> </message> <message> - <location line="+139"/> + <location line="+143"/> <source>Export Transaction Data</source> <translation>Export Transaction Data</translation> </message> @@ -2172,7 +2188,7 @@ Address: %4 <context> <name>WalletView</name> <message> - <location filename="../walletview.cpp" line="+42"/> + <location filename="../walletview.cpp" line="+46"/> <source>&Export</source> <translation>&Export</translation> </message> @@ -2182,7 +2198,7 @@ Address: %4 <translation>Export the data in the current tab to a file</translation> </message> <message> - <location line="+193"/> + <location line="+197"/> <source>Backup Wallet</source> <translation>Backup Wallet</translation> </message> @@ -2215,12 +2231,12 @@ Address: %4 <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+94"/> + <location filename="../bitcoinstrings.cpp" line="+98"/> <source>Bitcoin version</source> <translation>Bitcoin version</translation> </message> <message> - <location line="+102"/> + <location line="+103"/> <source>Usage:</source> <translation>Usage:</translation> </message> @@ -2235,12 +2251,12 @@ Address: %4 <translation>List commands</translation> </message> <message> - <location line="-12"/> + <location line="-13"/> <source>Get help for a command</source> <translation>Get help for a command</translation> </message> <message> - <location line="+24"/> + <location line="+25"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -2275,12 +2291,12 @@ Address: %4 <translation>Maintain at most <n> connections to peers (default: 125)</translation> </message> <message> - <location line="-48"/> + <location line="-49"/> <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="+82"/> + <location line="+83"/> <source>Specify your own public address</source> <translation>Specify your own public address</translation> </message> @@ -2290,17 +2306,17 @@ Address: %4 <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation> </message> <message> - <location line="-134"/> + <location line="-135"/> <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="-29"/> + <location line="-33"/> <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="+27"/> + <location line="+31"/> <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> @@ -2310,7 +2326,7 @@ Address: %4 <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="+76"/> + <location line="+77"/> <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> @@ -2320,12 +2336,12 @@ Address: %4 <translation>Use the test network</translation> </message> <message> - <location line="-112"/> + <location line="-113"/> <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="-80"/> + <location line="-84"/> <source>%s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2366,6 +2382,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <location line="+3"/> + <source>Enter regression test mode, which uses a special chain in which blocks can be solved instantly. This is intended for regression testing tools and app development.</source> + <translation>Enter regression test mode, which uses a special chain in which blocks can be solved instantly. This is intended for regression testing tools and app development.</translation> + </message> + <message> + <location line="+4"/> <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> @@ -2560,7 +2581,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>How thorough the block verification is (0-4, default: 3)</translation> </message> <message> - <location line="+19"/> + <location line="+2"/> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <location line="+18"/> <source>Not enough file descriptors available.</source> <translation>Not enough file descriptors available.</translation> </message> @@ -2585,7 +2611,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Verifying wallet...</translation> </message> <message> - <location line="-69"/> + <location line="+4"/> + <source>You need to rebuild the database using -reindex to change -txindex</source> + <translation>You need to rebuild the database using -reindex to change -txindex</translation> + </message> + <message> + <location line="-74"/> <source>Imports blocks from external blk000??.dat file</source> <translation>Imports blocks from external blk000??.dat file</translation> </message> @@ -2595,7 +2626,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)</translation> </message> <message> - <location line="+77"/> + <location line="+78"/> <source>Information</source> <translation>Information</translation> </message> @@ -2750,12 +2781,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Warning: This version is obsolete, upgrade required!</translation> </message> <message> - <location line="+1"/> - <source>You need to rebuild the databases using -reindex to change -txindex</source> - <translation>You need to rebuild the databases using -reindex to change -txindex</translation> - </message> - <message> - <location line="+1"/> + <location line="+2"/> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrupt, salvage failed</translation> </message> @@ -2765,22 +2791,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-67"/> + <location line="-68"/> <source>Allow JSON-RPC connections from specified IP address</source> <translation>Allow JSON-RPC connections from specified IP address</translation> </message> <message> - <location line="+76"/> + <location line="+77"/> <source>Send commands to node running on <ip> (default: 127.0.0.1)</source> <translation>Send commands to node running on <ip> (default: 127.0.0.1)</translation> </message> <message> - <location line="-120"/> + <location line="-121"/> <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="+147"/> + <location line="+148"/> <source>Upgrade wallet to latest format</source> <translation>Upgrade wallet to latest format</translation> </message> @@ -2810,12 +2836,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Server private key (default: server.pem)</translation> </message> <message> - <location line="-151"/> + <location line="-156"/> <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="+165"/> + <location line="+170"/> <source>This help message</source> <translation>This help message</translation> </message> @@ -2825,7 +2851,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation> </message> <message> - <location line="-91"/> + <location line="-92"/> <source>Connect through socks proxy</source> <translation>Connect through socks proxy</translation> </message> @@ -2835,12 +2861,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+55"/> + <location line="+56"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> <message> - <location line="-35"/> + <location line="-36"/> <source>Error loading wallet.dat: Wallet corrupted</source> <translation>Error loading wallet.dat: Wallet corrupted</translation> </message> @@ -2850,17 +2876,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Error loading wallet.dat: Wallet requires newer version of Bitcoin</translation> </message> <message> - <location line="+93"/> + <location line="+94"/> <source>Wallet needed to be rewritten: restart Bitcoin to complete</source> <translation>Wallet needed to be rewritten: restart Bitcoin to complete</translation> </message> <message> - <location line="-95"/> + <location line="-96"/> <source>Error loading wallet.dat</source> <translation>Error loading wallet.dat</translation> </message> <message> - <location line="+28"/> + <location line="+29"/> <source>Invalid -proxy address: '%s'</source> <translation>Invalid -proxy address: '%s'</translation> </message> @@ -2875,7 +2901,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unknown -socks proxy version requested: %i</translation> </message> <message> - <location line="-96"/> + <location line="-97"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -2885,7 +2911,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot resolve -externalip address: '%s'</translation> </message> <message> - <location line="+44"/> + <location line="+45"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</translation> </message> @@ -2905,7 +2931,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Loading block index...</translation> </message> <message> - <location line="-57"/> + <location line="-58"/> <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> @@ -2920,12 +2946,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Fee per KB to add to transactions you send</translation> </message> <message> - <location line="+19"/> + <location line="+20"/> <source>Loading wallet...</source> <translation>Loading wallet...</translation> </message> <message> - <location line="-52"/> + <location line="-53"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> @@ -2935,22 +2961,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot write default address</translation> </message> <message> - <location line="+64"/> + <location line="+65"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> <message> - <location line="-57"/> + <location line="-58"/> <source>Done loading</source> <translation>Done loading</translation> </message> <message> - <location line="+82"/> + <location line="+83"/> <source>To use the %s option</source> <translation>To use the %s option</translation> </message> <message> - <location line="-74"/> + <location line="-75"/> <source>Error</source> <translation>Error</translation> </message> diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 3c24016fe3..edaa732225 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -82,6 +82,15 @@ Value getblockcount(const Array& params, bool fHelp) return nBestHeight; } +Value getbestblockhash(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getbestblockhash\n" + "Returns the hash of the best (tip) block in the longest block chain."); + + return hashBestChain.GetHex(); +} Value getdifficulty(const Array& params, bool fHelp) { diff --git a/src/sync.h b/src/sync.h index 930c9b2b80..64de7cc57c 100644 --- a/src/sync.h +++ b/src/sync.h @@ -11,6 +11,48 @@ #include <boost/thread/condition_variable.hpp> #include "threadsafety.h" + +//////////////////////////////////////////////// +// // +// THE SIMPLE DEFINITON, EXCLUDING DEBUG CODE // +// // +//////////////////////////////////////////////// + +/* + + + +CCriticalSection mutex; + boost::recursive_mutex mutex; + +LOCK(mutex); + boost::unique_lock<boost::recursive_mutex> criticalblock(mutex); + +LOCK2(mutex1, mutex2); + boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1); + boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2); + +TRY_LOCK(mutex, name); + boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t); + +ENTER_CRITICAL_SECTION(mutex); // no RAII + mutex.lock(); + +LEAVE_CRITICAL_SECTION(mutex); // no RAII + mutex.unlock(); + + + + */ + + + +/////////////////////////////// +// // +// THE ACTUAL IMPLEMENTATION // +// // +/////////////////////////////// + // Template mixin that adds -Wthread-safety locking annotations to a // subset of the mutex API. template <typename PARENT> diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 23cb3a8e0a..3c666d2842 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -74,6 +74,7 @@ BOOST_AUTO_TEST_CASE(sign) } CTransaction txFrom; // Funding transaction: + string reason; txFrom.vout.resize(8); for (int i = 0; i < 4; i++) { @@ -82,7 +83,7 @@ BOOST_AUTO_TEST_CASE(sign) txFrom.vout[i+4].scriptPubKey = standardScripts[i]; txFrom.vout[i+4].nValue = COIN; } - BOOST_CHECK(IsStandardTx(txFrom)); + BOOST_CHECK(IsStandardTx(txFrom, reason)); CTransaction txTo[8]; // Spending transactions for (int i = 0; i < 8; i++) @@ -167,13 +168,14 @@ BOOST_AUTO_TEST_CASE(set) } CTransaction txFrom; // Funding transaction: + string reason; txFrom.vout.resize(4); for (int i = 0; i < 4; i++) { txFrom.vout[i].scriptPubKey = outer[i]; txFrom.vout[i].nValue = CENT; } - BOOST_CHECK(IsStandardTx(txFrom)); + BOOST_CHECK(IsStandardTx(txFrom, reason)); CTransaction txTo[4]; // Spending transactions for (int i = 0; i < 4; i++) @@ -189,7 +191,7 @@ BOOST_AUTO_TEST_CASE(set) for (int i = 0; i < 4; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); - BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i]), strprintf("txTo[%d].IsStandard", i)); + BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); } } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 53d1307b69..0c7475b4f2 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -260,16 +260,17 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) key.MakeNewKey(true); t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); - BOOST_CHECK(IsStandardTx(t)); + string reason; + BOOST_CHECK(IsStandardTx(t, reason)); t.vout[0].nValue = 5011; // dust - BOOST_CHECK(!IsStandardTx(t)); + BOOST_CHECK(!IsStandardTx(t, reason)); t.vout[0].nValue = 6011; // not dust - BOOST_CHECK(IsStandardTx(t)); + BOOST_CHECK(IsStandardTx(t, reason)); t.vout[0].scriptPubKey = CScript() << OP_1; - BOOST_CHECK(!IsStandardTx(t)); + BOOST_CHECK(!IsStandardTx(t, reason)); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 64bd3a1b28..fd936517fd 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -263,28 +263,10 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { - // Expected results for the determinstic seed. - const uint32_t exp_vals[11] = { 91632771U,1889679809U,3842137544U,3256031132U, - 1761911779U, 489223532U,2692793790U,2737472863U, - 2796262275U,1309899767U,840571781U}; - // Expected 0s in rand()%(idx+2) for the determinstic seed. - const int exp_count[9] = {5013,3346,2415,1972,1644,1386,1176,1096,1009}; int i; int count=0; - seed_insecure_rand(); - - //Does the non-determistic rand give us results that look too like the determinstic one? - for (i=0;i<10;i++) - { - int match = 0; - uint32_t rval = insecure_rand(); - for (int j=0;j<11;j++)match |= rval==exp_vals[j]; - count += match; - } - // sum(binomial(10,i)*(11/(2^32))^i*(1-(11/(2^32)))^(10-i),i,0,4) ~= 1-1/2^134.73 - // So _very_ unlikely to throw a false failure here. - BOOST_CHECK(count<=4); + seed_insecure_rand(true); for (int mod=2;mod<11;mod++) { @@ -307,20 +289,6 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) BOOST_CHECK(count<=10000/mod+err); BOOST_CHECK(count>=10000/mod-err); } - - seed_insecure_rand(true); - - for (i=0;i<11;i++) - { - BOOST_CHECK_EQUAL(insecure_rand(),exp_vals[i]); - } - - for (int mod=2;mod<11;mod++) - { - count = 0; - for (i=0;i<10000;i++) count += insecure_rand()%mod==0; - BOOST_CHECK_EQUAL(count,exp_count[mod-2]); - } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/version.cpp b/src/version.cpp index 8af406feab..d9d6724a02 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -36,7 +36,7 @@ const std::string CLIENT_NAME("Satoshi"); // git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$ #ifdef GIT_ARCHIVE # define GIT_COMMIT_ID "$Format:%h$" -# define GIT_COMMIT_DATE "$Format:%cD" +# define GIT_COMMIT_DATE "$Format:%cD$" #endif #define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \ diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 702e219a5b..7aad779767 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -5,6 +5,7 @@ #include "walletdb.h" #include "wallet.h" +#include <boost/version.hpp> #include <boost/filesystem.hpp> using namespace std; |