diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bitcoinrpc.cpp | 1 | ||||
-rw-r--r-- | src/bitcoinrpc.h | 1 | ||||
-rw-r--r-- | src/core.cpp | 294 | ||||
-rw-r--r-- | src/core.h | 249 | ||||
-rw-r--r-- | src/db.cpp | 1 | ||||
-rw-r--r-- | src/init.cpp | 6 | ||||
-rw-r--r-- | src/key.cpp | 5 | ||||
-rw-r--r-- | src/main.cpp | 104 | ||||
-rw-r--r-- | src/main.h | 4 | ||||
-rw-r--r-- | src/makefile.mingw | 2 | ||||
-rw-r--r-- | src/net.cpp | 4 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 100 | ||||
-rw-r--r-- | src/qt/bitcoinstrings.cpp | 5 | ||||
-rw-r--r-- | src/qt/forms/intro.ui | 266 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 3 | ||||
-rw-r--r-- | src/qt/intro.cpp | 270 | ||||
-rw-r--r-- | src/qt/intro.h | 67 | ||||
-rw-r--r-- | src/qt/locale/bitcoin_en.ts | 210 | ||||
-rw-r--r-- | src/rpcblockchain.cpp | 9 | ||||
-rw-r--r-- | src/sync.h | 42 | ||||
-rw-r--r-- | src/test/script_P2SH_tests.cpp | 8 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 9 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 34 | ||||
-rw-r--r-- | src/version.cpp | 2 | ||||
-rw-r--r-- | src/walletdb.cpp | 1 |
25 files changed, 1225 insertions, 472 deletions
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; |