aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitcoinrpc.cpp6
-rw-r--r--src/bitcoinrpc.h5
-rw-r--r--src/bloom.cpp2
-rw-r--r--src/chainparams.cpp3
-rw-r--r--src/core.cpp294
-rw-r--r--src/core.h236
-rw-r--r--src/init.cpp20
-rw-r--r--src/main.cpp292
-rw-r--r--src/main.h213
-rw-r--r--src/makefile.linux-mingw3
-rw-r--r--src/makefile.mingw3
-rw-r--r--src/makefile.osx3
-rw-r--r--src/net.cpp5
-rw-r--r--src/qt/bitcoinamountfield.cpp10
-rw-r--r--src/qt/bitcoinstrings.cpp5
-rw-r--r--src/qt/bitcoinunits.cpp11
-rw-r--r--src/qt/bitcoinunits.h2
-rw-r--r--src/qt/locale/bitcoin_en.ts210
-rw-r--r--src/rpcblockchain.cpp27
-rw-r--r--src/rpcdump.cpp206
-rw-r--r--src/rpcmining.cpp1
-rw-r--r--src/rpcrawtransaction.cpp1
-rw-r--r--src/script.cpp36
-rw-r--r--src/script.h1
-rw-r--r--src/sync.h42
-rw-r--r--src/test/checkblock_tests.cpp2
-rw-r--r--src/test/util_tests.cpp34
-rw-r--r--src/util.h4
-rw-r--r--src/version.cpp2
-rw-r--r--src/wallet.cpp54
-rw-r--r--src/wallet.h4
-rw-r--r--src/walletdb.cpp9
32 files changed, 1089 insertions, 657 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index febb475db3..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 },
@@ -243,7 +244,9 @@ static const CRPCCommand vRPCCommands[] =
{ "submitblock", &submitblock, false, false },
{ "listsinceblock", &listsinceblock, false, false },
{ "dumpprivkey", &dumpprivkey, true, false },
+ { "dumpwallet", &dumpwallet, true, false },
{ "importprivkey", &importprivkey, false, false },
+ { "importwallet", &importwallet, false, false },
{ "listunspent", &listunspent, false, false },
{ "getrawtransaction", &getrawtransaction, false, false },
{ "createrawtransaction", &createrawtransaction, false, false },
@@ -254,6 +257,7 @@ static const CRPCCommand vRPCCommands[] =
{ "gettxout", &gettxout, true, false },
{ "lockunspent", &lockunspent, false, false },
{ "listlockunspent", &listlockunspent, false, false },
+ { "verifychain", &verifychain, true, false },
};
CRPCTable::CRPCTable()
@@ -1194,6 +1198,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
+ if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]);
return params;
}
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 44c657f8dc..4d5599be84 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -145,8 +145,11 @@ extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, b
extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp);
+
extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp
extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp);
@@ -198,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);
@@ -205,5 +209,6 @@ extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fH
extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
#endif
diff --git a/src/bloom.cpp b/src/bloom.cpp
index d9ec2efa81..b6799e143d 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -5,7 +5,7 @@
#include <stdlib.h>
#include "bloom.h"
-#include "main.h"
+#include "core.h"
#include "script.h"
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 8859424d20..3bb62fb793 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -6,7 +6,8 @@
#include "assert.h"
#include "chainparams.h"
-#include "main.h"
+#include "core.h"
+#include "protocol.h"
#include "util.h"
//
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 c568fd2ef9..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
{
@@ -733,4 +592,63 @@ public:
}
};
+
+class CBlock : public CBlockHeader
+{
+public:
+ // network and disk
+ std::vector<CTransaction> vtx;
+
+ // memory only
+ mutable std::vector<uint256> vMerkleTree;
+
+ CBlock()
+ {
+ SetNull();
+ }
+
+ CBlock(const CBlockHeader &header)
+ {
+ SetNull();
+ *((CBlockHeader*)this) = header;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ READWRITE(*(CBlockHeader*)this);
+ READWRITE(vtx);
+ )
+
+ void SetNull()
+ {
+ CBlockHeader::SetNull();
+ vtx.clear();
+ vMerkleTree.clear();
+ }
+
+ CBlockHeader GetBlockHeader() const
+ {
+ CBlockHeader block;
+ block.nVersion = nVersion;
+ block.hashPrevBlock = hashPrevBlock;
+ block.hashMerkleRoot = hashMerkleRoot;
+ block.nTime = nTime;
+ block.nBits = nBits;
+ block.nNonce = nNonce;
+ return block;
+ }
+
+ uint256 BuildMerkleTree() const;
+
+ const uint256 &GetTxHash(unsigned int nIndex) const {
+ assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
+ assert(nIndex < vtx.size());
+ return vMerkleTree[nIndex];
+ }
+
+ 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/init.cpp b/src/init.cpp
index 4e599048ac..f6b2c91b40 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -14,7 +14,6 @@
#include "util.h"
#include "ui_interface.h"
#include "checkpoints.h"
-#include "chainparams.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -120,7 +119,7 @@ void Shutdown()
}
bitdb.Flush(true);
boost::filesystem::remove(GetPidFile());
- UnregisterWallet(pwalletMain);
+ UnregisterAllWallets();
delete pwalletMain;
}
@@ -750,20 +749,21 @@ bool AppInit2(boost::thread_group& threadGroup)
if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL)
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
- // Check for changed -txindex state (only necessary if we are not reindexing anyway)
- if (!fReindex && fTxIndex != GetBoolArg("-txindex", false)) {
- strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
- break;
- }
-
// Initialize the block index (no-op if non-empty database was already loaded)
if (!InitBlockIndex()) {
strLoadError = _("Error initializing block database");
break;
}
+ // Check for changed -txindex state
+ if (fTxIndex != GetBoolArg("-txindex", false)) {
+ strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
+ break;
+ }
+
uiInterface.InitMessage(_("Verifying blocks..."));
- if (!VerifyDB()) {
+ if (!VerifyDB(GetArg("-checklevel", 3),
+ GetArg( "-checkblocks", 288))) {
strLoadError = _("Corrupted block database detected");
break;
}
@@ -820,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup)
{
CBlockIndex* pindex = (*mi).second;
CBlock block;
- block.ReadFromDisk(pindex);
+ ReadBlockFromDisk(block, pindex);
block.BuildMerkleTree();
block.print();
printf("\n");
diff --git a/src/main.cpp b/src/main.cpp
index 3879b78ad4..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();
}
@@ -642,7 +656,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if (pcoinsTip->GetCoins(GetHash(), coins)) {
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
if (pindex) {
- if (!blockTmp.ReadFromDisk(pindex))
+ if (!ReadBlockFromDisk(blockTmp, pindex))
return 0;
pblock = &blockTmp;
}
@@ -1131,7 +1145,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
if (pindexSlow) {
CBlock block;
- if (block.ReadFromDisk(pindexSlow)) {
+ if (ReadBlockFromDisk(block, pindexSlow)) {
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
if (tx.GetHash() == hash) {
txOut = tx;
@@ -1163,12 +1177,62 @@ CBlockIndex* FindBlockByHeight(int nHeight)
return vBlockIndexByHeight[nHeight];
}
-bool CBlock::ReadFromDisk(const CBlockIndex* pindex)
+bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
+{
+ // Open history file to append
+ CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ return error("WriteBlockToDisk() : OpenBlockFile failed");
+
+ // Write index header
+ unsigned int nSize = fileout.GetSerializeSize(block);
+ fileout << FLATDATA(Params().MessageStart()) << nSize;
+
+ // Write block
+ long fileOutPos = ftell(fileout);
+ if (fileOutPos < 0)
+ return error("WriteBlockToDisk() : ftell failed");
+ pos.nPos = (unsigned int)fileOutPos;
+ fileout << block;
+
+ // Flush stdio buffers and commit to disk before returning
+ fflush(fileout);
+ if (!IsInitialBlockDownload())
+ FileCommit(fileout);
+
+ return true;
+}
+
+bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
+{
+ block.SetNull();
+
+ // Open history file to read
+ CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed");
+
+ // Read block
+ try {
+ filein >> block;
+ }
+ catch (std::exception &e) {
+ return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+ }
+
+ // Check the header
+ if (!CheckProofOfWork(block.GetHash(), block.nBits))
+ return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header");
+
+ return true;
+}
+
+bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
{
- if (!ReadFromDisk(pindex->GetBlockPos()))
+ if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
return false;
- if (GetHash() != pindex->GetBlockHash())
- return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
+ if (block.GetHash() != pindex->GetBlockHash())
+ return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index");
return true;
}
@@ -1570,7 +1634,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
-bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
+bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
assert(pindex == view.GetBestBlock());
@@ -1586,12 +1650,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
return error("DisconnectBlock() : failure reading undo data");
- if (blockUndo.vtxundo.size() + 1 != vtx.size())
+ if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
return error("DisconnectBlock() : block and undo data inconsistent");
// undo transactions in reverse order
- for (int i = vtx.size() - 1; i >= 0; i--) {
- const CTransaction &tx = vtx[i];
+ for (int i = block.vtx.size() - 1; i >= 0; i--) {
+ const CTransaction &tx = block.vtx[i];
uint256 hash = tx.GetHash();
// check that all outputs are available
@@ -1684,10 +1748,10 @@ void ThreadScriptCheck() {
scriptcheckqueue.Thread();
}
-bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck)
+bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
{
// Check it again in case a previous version let a bad block in
- if (!CheckBlock(state, !fJustCheck, !fJustCheck))
+ if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
return false;
// verify that the view's current state corresponds to the previous block
@@ -1695,7 +1759,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
- if (GetHash() == Params().HashGenesisBlock()) {
+ if (block.GetHash() == Params().HashGenesisBlock()) {
view.SetBestBlock(pindex);
pindexGenesisBlock = pindex;
return true;
@@ -1719,8 +1783,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
if (fEnforceBIP30) {
- for (unsigned int i=0; i<vtx.size(); i++) {
- uint256 hash = GetTxHash(i);
+ for (unsigned int i = 0; i < block.vtx.size(); i++) {
+ uint256 hash = block.GetTxHash(i);
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
}
@@ -1741,12 +1805,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
int64 nFees = 0;
int nInputs = 0;
unsigned int nSigOps = 0;
- CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size()));
+ CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
- vPos.reserve(vtx.size());
- for (unsigned int i=0; i<vtx.size(); i++)
+ vPos.reserve(block.vtx.size());
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- const CTransaction &tx = vtx[i];
+ const CTransaction &tx = block.vtx[i];
nInputs += tx.vin.size();
nSigOps += GetLegacySigOpCount(tx);
@@ -1777,19 +1841,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
}
CTxUndo txundo;
- UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i));
+ UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
- vPos.push_back(std::make_pair(GetTxHash(i), pos));
+ vPos.push_back(std::make_pair(block.GetTxHash(i), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark)
- printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
+ printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
- if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
- return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
+ if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
+ return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
if (!control.Wait())
return state.DoS(100, false);
@@ -1830,8 +1894,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
assert(view.SetBestBlock(pindex));
// Watch for transactions paying to me
- for (unsigned int i=0; i<vtx.size(); i++)
- SyncWithWallets(GetTxHash(i), vtx[i], this, true);
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
+ SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true);
return true;
}
@@ -1877,10 +1941,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector<CTransaction> vResurrect;
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
CBlock block;
- if (!block.ReadFromDisk(pindex))
+ if (!ReadBlockFromDisk(block, pindex))
return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros();
- if (!block.DisconnectBlock(state, pindex, view))
+ if (!DisconnectBlock(block, state, pindex, view))
return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
if (fBenchmark)
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
@@ -1897,10 +1961,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector<CTransaction> vDelete;
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
CBlock block;
- if (!block.ReadFromDisk(pindex))
+ if (!ReadBlockFromDisk(block, pindex))
return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros();
- if (!block.ConnectBlock(state, pindex, view)) {
+ if (!ConnectBlock(block, state, pindex, view)) {
if (state.IsInvalid()) {
InvalidChainFound(pindexNew);
InvalidBlockFound(pindex);
@@ -2010,25 +2074,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
}
-bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
+bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos)
{
// Check for duplicate
- uint256 hash = GetHash();
+ uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str()));
// Construct new block index object
- CBlockIndex* pindexNew = new CBlockIndex(*this);
+ CBlockIndex* pindexNew = new CBlockIndex(block);
assert(pindexNew);
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
- map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
+ map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
if (miPrev != mapBlockIndex.end())
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
}
- pindexNew->nTx = vtx.size();
+ pindexNew->nTx = block.vtx.size();
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256();
pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
pindexNew->nFile = pos.nFile;
@@ -2049,7 +2113,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
UpdatedTransaction(hashPrevBestCoinBase);
- hashPrevBestCoinBase = GetTxHash(0);
+ hashPrevBestCoinBase = block.GetTxHash(0);
}
if (!pblocktree->Flush())
@@ -2155,51 +2219,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
}
-bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const
+bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// Size limits
- if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
+ if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
- if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits))
+ if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
return state.DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp
- if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
+ if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"));
// First transaction must be coinbase, the rest must not be
- if (vtx.empty() || !vtx[0].IsCoinBase())
+ if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"));
- for (unsigned int i = 1; i < vtx.size(); i++)
- if (vtx[i].IsCoinBase())
+ for (unsigned int i = 1; i < block.vtx.size(); i++)
+ if (block.vtx[i].IsCoinBase())
return state.DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions
- BOOST_FOREACH(const CTransaction& tx, vtx)
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
// Build the merkle tree already. We need it anyway later, and it makes the
// block cache the transaction hashes, which means they don't need to be
// recalculated many times during this block's validation.
- BuildMerkleTree();
+ block.BuildMerkleTree();
// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
set<uint256> uniqueTx;
- for (unsigned int i=0; i<vtx.size(); i++) {
- uniqueTx.insert(GetTxHash(i));
+ for (unsigned int i = 0; i < block.vtx.size(); i++) {
+ uniqueTx.insert(block.GetTxHash(i));
}
- if (uniqueTx.size() != vtx.size())
+ if (uniqueTx.size() != block.vtx.size())
return state.DoS(100, error("CheckBlock() : duplicate transaction"));
unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTransaction& tx, vtx)
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
{
nSigOps += GetLegacySigOpCount(tx);
}
@@ -2207,16 +2271,16 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkle root
- if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
+ if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
}
-bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
+bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
{
// Check for duplicate
- uint256 hash = GetHash();
+ uint256 hash = block.GetHash();
if (mapBlockIndex.count(hash))
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
@@ -2224,23 +2288,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
CBlockIndex* pindexPrev = NULL;
int nHeight = 0;
if (hash != Params().HashGenesisBlock()) {
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
return state.DoS(10, error("AcceptBlock() : prev block not found"));
pindexPrev = (*mi).second;
nHeight = pindexPrev->nHeight+1;
// Check proof of work
- if (nBits != GetNextWorkRequired(pindexPrev, this))
+ if (block.nBits != GetNextWorkRequired(pindexPrev, &block))
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
- if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
+ if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
// Check that all transactions are finalized
- BOOST_FOREACH(const CTransaction& tx, vtx)
- if (!IsFinalTx(tx, nHeight, GetBlockTime()))
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"));
// Check that the block chain matches the known block chain up to a checkpoint
@@ -2248,7 +2312,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
- if (nVersion < 2)
+ if (block.nVersion < 2)
{
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
@@ -2257,14 +2321,14 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
}
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
- if (nVersion >= 2)
+ if (block.nVersion >= 2)
{
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
{
CScript expect = CScript() << nHeight;
- if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
+ if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
}
}
@@ -2272,16 +2336,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
// Write block to history file
try {
- unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
+ unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
if (dbp != NULL)
blockPos = *dbp;
- if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL))
return error("AcceptBlock() : FindBlockPos failed");
if (dbp == NULL)
- if (!WriteToDisk(blockPos))
+ if (!WriteBlockToDisk(block, blockPos))
return state.Abort(_("Failed to write block"));
- if (!AddToBlockIndex(state, blockPos))
+ if (!AddToBlockIndex(block, state, blockPos))
return error("AcceptBlock() : AddToBlockIndex failed");
} catch(std::runtime_error &e) {
return state.Abort(_("System error: ") + e.what());
@@ -2333,7 +2397,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str()));
// Preliminary checks
- if (!pblock->CheckBlock(state))
+ if (!CheckBlock(*pblock, state))
return error("ProcessBlock() : CheckBlock FAILED");
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
@@ -2374,7 +2438,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
}
// Store to disk
- if (!pblock->AcceptBlock(state, dbp))
+ if (!AcceptBlock(*pblock, state, dbp))
return error("ProcessBlock() : AcceptBlock FAILED");
// Recursively process any orphan blocks that depended on this one
@@ -2390,7 +2454,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
CBlock* pblockOrphan = (*mi).second;
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
CValidationState stateDummy;
- if (pblockOrphan->AcceptBlock(stateDummy))
+ if (AcceptBlock(*pblockOrphan, stateDummy))
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
@@ -2703,14 +2767,13 @@ bool static LoadBlockIndexDB()
return true;
}
-bool VerifyDB() {
+bool VerifyDB(int nCheckLevel, int nCheckDepth)
+{
if (pindexBest == NULL || pindexBest->pprev == NULL)
return true;
// Verify blocks in the best chain
- int nCheckLevel = GetArg("-checklevel", 3);
- int nCheckDepth = GetArg( "-checkblocks", 288);
- if (nCheckDepth == 0)
+ if (nCheckDepth <= 0)
nCheckDepth = 1000000000; // suffices until the year 19000
if (nCheckDepth > nBestHeight)
nCheckDepth = nBestHeight;
@@ -2728,10 +2791,10 @@ bool VerifyDB() {
break;
CBlock block;
// check level 0: read from disk
- if (!block.ReadFromDisk(pindex))
- return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ if (!ReadBlockFromDisk(block, pindex))
+ return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 1: verify block validity
- if (nCheckLevel >= 1 && !block.CheckBlock(state))
+ if (nCheckLevel >= 1 && !CheckBlock(block, state))
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
@@ -2745,7 +2808,7 @@ bool VerifyDB() {
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
bool fClean = true;
- if (!block.DisconnectBlock(state, pindex, coins, &fClean))
+ if (!DisconnectBlock(block, state, pindex, coins, &fClean))
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
pindexState = pindex->pprev;
if (!fClean) {
@@ -2765,9 +2828,9 @@ bool VerifyDB() {
boost::this_thread::interruption_point();
pindex = pindex->GetNextInMainChain();
CBlock block;
- if (!block.ReadFromDisk(pindex))
- return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
- if (!block.ConnectBlock(state, pindex, coins))
+ if (!ReadBlockFromDisk(block, pindex))
+ return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ if (!ConnectBlock(block, state, pindex, coins))
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
}
}
@@ -2818,9 +2881,9 @@ bool InitBlockIndex() {
CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
return error("LoadBlockIndex() : FindBlockPos failed");
- if (!block.WriteToDisk(blockPos))
+ if (!WriteBlockToDisk(block, blockPos))
return error("LoadBlockIndex() : writing genesis block to disk failed");
- if (!block.AddToBlockIndex(state, blockPos))
+ if (!AddToBlockIndex(block, state, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
} catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
@@ -2876,7 +2939,7 @@ void PrintBlockTree()
// print item
CBlock block;
- block.ReadFromDisk(pindex);
+ ReadBlockFromDisk(block, pindex);
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
pindex->nHeight,
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
@@ -3100,7 +3163,7 @@ void static ProcessGetData(CNode* pfrom)
if (mi != mapBlockIndex.end())
{
CBlock block;
- block.ReadFromDisk((*mi).second);
+ ReadBlockFromDisk(block, (*mi).second);
if (inv.type == MSG_BLOCK)
pfrom->PushMessage("block", block);
else // MSG_FILTERED_BLOCK)
@@ -3535,6 +3598,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_TX, tx.GetHash());
pfrom->AddInventoryKnown(inv);
+ // Truncate messages to the size of the tx in them
+ unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
+ unsigned int oldSize = vMsg.size();
+ if (nSize < oldSize) {
+ vMsg.resize(nSize);
+ printf("truncating oversized TX %s (%u -> %u)\n",
+ tx.GetHash().ToString().c_str(),
+ oldSize, nSize);
+ }
+
bool fMissingInputs = false;
CValidationState state;
if (mempool.accept(state, tx, true, &fMissingInputs))
@@ -4422,7 +4495,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
indexDummy.nHeight = pindexPrev->nHeight + 1;
CCoinsViewCache viewNew(*pcoinsTip, true);
CValidationState state;
- if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true))
+ if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
}
@@ -4705,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 b9879d1097..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);
@@ -146,7 +148,7 @@ bool LoadBlockIndex();
/** Unload database information */
void UnloadBlockIndex();
/** Verify consistency of the block and coin databases */
-bool VerifyDB();
+bool VerifyDB(int nCheckLevel, int nCheckDepth);
/** Print the loaded block tree */
void PrintBlockTree();
/** Find a block by height in the currently-connected chain */
@@ -581,204 +583,33 @@ public:
};
-class CBlock : public CBlockHeader
-{
-public:
- // network and disk
- std::vector<CTransaction> vtx;
-
- // memory only
- mutable std::vector<uint256> vMerkleTree;
-
- CBlock()
- {
- SetNull();
- }
-
- CBlock(const CBlockHeader &header)
- {
- SetNull();
- *((CBlockHeader*)this) = header;
- }
-
- IMPLEMENT_SERIALIZE
- (
- READWRITE(*(CBlockHeader*)this);
- READWRITE(vtx);
- )
-
- void SetNull()
- {
- CBlockHeader::SetNull();
- vtx.clear();
- vMerkleTree.clear();
- }
-
- CBlockHeader GetBlockHeader() const
- {
- CBlockHeader block;
- block.nVersion = nVersion;
- block.hashPrevBlock = hashPrevBlock;
- block.hashMerkleRoot = hashMerkleRoot;
- block.nTime = nTime;
- block.nBits = nBits;
- block.nNonce = nNonce;
- 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());
- }
-
- const uint256 &GetTxHash(unsigned int nIndex) const {
- assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
- assert(nIndex < vtx.size());
- 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;
- }
-
- bool WriteToDisk(CDiskBlockPos &pos)
- {
- // Open history file to append
- CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
- if (!fileout)
- return error("CBlock::WriteToDisk() : OpenBlockFile failed");
-
- // Write index header
- unsigned int nSize = fileout.GetSerializeSize(*this);
- fileout << FLATDATA(Params().MessageStart()) << nSize;
-
- // Write block
- long fileOutPos = ftell(fileout);
- if (fileOutPos < 0)
- return error("CBlock::WriteToDisk() : ftell failed");
- pos.nPos = (unsigned int)fileOutPos;
- fileout << *this;
-
- // Flush stdio buffers and commit to disk before returning
- fflush(fileout);
- if (!IsInitialBlockDownload())
- FileCommit(fileout);
-
- return true;
- }
-
- bool ReadFromDisk(const CDiskBlockPos &pos)
- {
- SetNull();
-
- // Open history file to read
- CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
- if (!filein)
- return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
- // Read block
- try {
- filein >> *this;
- }
- catch (std::exception &e) {
- return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
- }
+/** Functions for disk access for blocks */
+bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
+bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
+bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
- // Check the header
- if (!CheckProofOfWork(GetHash(), nBits))
- return error("CBlock::ReadFromDisk() : errors in block header");
- return true;
- }
+/** Functions for validating blocks and updating the block tree */
+/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
+ * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
+ * will be true if no problems were found. Otherwise, the return value will be false in case
+ * of problems. Note that in any case, coins may be modified. */
+bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
+// Apply the effects of this block (with given index) on the UTXO set represented by coins
+bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
- 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");
- }
-
-
- /** Undo the effects of this block (with given index) on the UTXO set represented by coins.
- * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
- * will be true if no problems were found. Otherwise, the return value will be false in case
- * of problems. Note that in any case, coins may be modified. */
- bool DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL);
-
- // Apply the effects of this block (with given index) on the UTXO set represented by coins
- bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false);
-
- // Read a block from disk
- bool ReadFromDisk(const CBlockIndex* pindex);
-
- // Add this block to the block index, and if necessary, switch the active block chain to this
- bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos);
-
- // Context-independent validity checks
- bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const;
-
- // Store block on disk
- // if dbp is provided, the file is known to already reside on disk
- bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL);
-};
+// Add this block to the block index, and if necessary, switch the active block chain to this
+bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
+// Context-independent validity checks
+bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
+// Store block on disk
+// if dbp is provided, the file is known to already reside on disk
+bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL);
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 9cfab5942a..26d541664e 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -93,7 +93,8 @@ OBJS= \
obj/hash.o \
obj/bloom.o \
obj/leveldb.o \
- obj/txdb.o
+ obj/txdb.o \
+ obj/chainparams.o
all: bitcoind.exe
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 33cc7e6b4a..3659f52040 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -101,7 +101,8 @@ OBJS= \
obj/bloom.o \
obj/noui.o \
obj/leveldb.o \
- obj/txdb.o
+ obj/txdb.o \
+ obj/chainparams.o
all: bitcoind.exe
diff --git a/src/makefile.osx b/src/makefile.osx
index bef0ef3518..269460c1ba 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -104,7 +104,8 @@ OBJS= \
obj/bloom.o \
obj/noui.o \
obj/leveldb.o \
- obj/txdb.o
+ obj/txdb.o \
+ obj/chainparams.o
ifndef USE_UPNP
override USE_UPNP = -
diff --git a/src/net.cpp b/src/net.cpp
index 0adf26ef0d..5418c3de40 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -22,6 +22,9 @@
#include <miniupnpc/upnperrors.h>
#endif
+// Dump addresses to peers.dat every 15 minutes (900s)
+#define DUMP_ADDRESSES_INTERVAL 900
+
using namespace std;
using namespace boost;
@@ -1730,7 +1733,7 @@ void StartNode(boost::thread_group& threadGroup)
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
// Dump network addresses
- threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 10000));
+ threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, DUMP_ADDRESSES_INTERVAL * 1000));
}
bool StopNode()
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index b12e296f99..b502505f31 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -60,7 +60,9 @@ bool BitcoinAmountField::validate()
bool valid = true;
if (amount->value() == 0.0)
valid = false;
- if (valid && !BitcoinUnits::parse(currentUnit, text(), 0))
+ else if (!BitcoinUnits::parse(currentUnit, text(), 0))
+ valid = false;
+ else if (amount->value() > BitcoinUnits::maxAmount(currentUnit))
valid = false;
setValid(valid);
@@ -115,7 +117,7 @@ qint64 BitcoinAmountField::value(bool *valid_out) const
{
qint64 val_out = 0;
bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
- if(valid_out)
+ if (valid_out)
{
*valid_out = valid;
}
@@ -145,12 +147,12 @@ void BitcoinAmountField::unitChanged(int idx)
amount->setDecimals(BitcoinUnits::decimals(currentUnit));
amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals()));
- if(currentUnit == BitcoinUnits::uBTC)
+ if (currentUnit == BitcoinUnits::uBTC)
amount->setSingleStep(0.01);
else
amount->setSingleStep(0.001);
- if(valid)
+ if (valid)
{
// If value was valid, re-place it in the widget with the new unit
setValue(currentValue);
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/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index d4715abaec..ae9791123d 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -63,6 +63,17 @@ qint64 BitcoinUnits::factor(int unit)
}
}
+qint64 BitcoinUnits::maxAmount(int unit)
+{
+ switch(unit)
+ {
+ case BTC: return Q_INT64_C(21000000);
+ case mBTC: return Q_INT64_C(21000000000);
+ case uBTC: return Q_INT64_C(21000000000000);
+ default: return 0;
+ }
+}
+
int BitcoinUnits::amountDigits(int unit)
{
switch(unit)
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 6e96cef59d..f6fdf6c7be 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -38,6 +38,8 @@ public:
static QString description(int unit);
//! Number of Satoshis (1e-8) per unit
static qint64 factor(int unit);
+ //! Max amount per unit
+ static qint64 maxAmount(int unit);
//! Number of amount digits (to represent max number of coins)
static int amountDigits(int unit);
//! Number of decimals left
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 &amp;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 &amp;message...</source>
<translation>Sign &amp;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>&amp;Overview</source>
<translation>&amp;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>&amp;Options...</translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+9"/>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Encrypt Wallet...</translation>
</message>
@@ -410,7 +410,7 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>&amp;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>&amp;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>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
@@ -481,12 +483,14 @@ This product includes software developed by the OpenSSL Project for use in the O
<translation>&amp;Addresses</translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+23"/>
+ <location line="+2"/>
<source>&amp;About Bitcoin</source>
<translation>&amp;About Bitcoin</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+10"/>
+ <location line="+2"/>
<source>&amp;Show / Hide</source>
<translation>&amp;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 &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</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>&amp;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>&lt;b&gt;Recent transactions&lt;/b&gt;</source>
- <translation>&lt;b&gt;Recent transactions&lt;/b&gt;</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>&lt;b&gt;Recent transactions&lt;/b&gt;</source>
+ <translation>&lt;b&gt;Recent transactions&lt;/b&gt;</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>&amp;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&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-59"/>
+ <location filename="../sendcoinsdialog.cpp" line="-62"/>
+ <location line="+2"/>
<source>&lt;b&gt;%1&lt;/b&gt; to %2 (%3)</source>
<translation>&lt;b&gt;%1&lt;/b&gt; 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>&amp;Export</source>
<translation>&amp;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 &lt;n&gt; 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 &lt;port&gt; (default: 8332 or testnet: 18332)</source>
<translation>Listen for JSON-RPC connections on &lt;port&gt; (default: 8332 or testnet: 18332)</translation>
</message>
@@ -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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; admin@foo.
<translation>Set the number of script verification threads (up to 16, 0 = auto, &lt;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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 &lt;ip&gt; (default: 127.0.0.1)</source>
<translation>Send commands to node running on &lt;ip&gt; (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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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: &apos;%s&apos;</source>
<translation>Invalid -proxy address: &apos;%s&apos;</translation>
</message>
@@ -2875,7 +2901,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Unknown -socks proxy version requested: %i</translation>
</message>
<message>
- <location line="-96"/>
+ <location line="-97"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -2885,7 +2911,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Cannot resolve -externalip address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+44"/>
+ <location line="+45"/>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</source>
<translation>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos;</translation>
</message>
@@ -2905,7 +2931,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 &quot;Bitcoin Alert&quot; 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 a0ddc4d9ee..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)
{
@@ -163,7 +172,7 @@ Value getblock(const Array& params, bool fHelp)
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
- block.ReadFromDisk(pblockindex);
+ ReadBlockFromDisk(block, pblockindex);
if (!fVerbose)
{
@@ -243,4 +252,20 @@ Value gettxout(const Array& params, bool fHelp)
return ret;
}
+Value verifychain(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 2)
+ throw runtime_error(
+ "verifychain [check level] [num blocks]\n"
+ "Verifies blockchain database.");
+
+ int nCheckLevel = GetArg("-checklevel", 3);
+ int nCheckDepth = GetArg("-checkblocks", 288);
+ if (params.size() > 0)
+ nCheckLevel = params[0].get_int();
+ if (params.size() > 1)
+ nCheckDepth = params[1].get_int();
+
+ return VerifyDB(nCheckLevel, nCheckDepth);
+}
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index d46309eaa4..dcfb023f35 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -2,35 +2,68 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <iostream>
+#include <fstream>
+
#include "init.h" // for pwalletMain
#include "bitcoinrpc.h"
#include "ui_interface.h"
#include "base58.h"
+#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/variant/get.hpp>
+#include <boost/algorithm/string.hpp>
#define printf OutputDebugStringF
using namespace json_spirit;
using namespace std;
-class CTxDump
-{
-public:
- CBlockIndex *pindex;
- int64 nValue;
- bool fSpent;
- CWalletTx* ptx;
- int nOut;
- CTxDump(CWalletTx* ptx = NULL, int nOut = -1)
- {
- pindex = NULL;
- nValue = 0;
- fSpent = false;
- this->ptx = ptx;
- this->nOut = nOut;
+void EnsureWalletIsUnlocked();
+
+std::string static EncodeDumpTime(int64 nTime) {
+ return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
+}
+
+int64 static DecodeDumpTime(const std::string &str) {
+ static const boost::posix_time::time_input_facet facet("%Y-%m-%dT%H:%M:%SZ");
+ static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
+ const std::locale loc(std::locale::classic(), &facet);
+ std::istringstream iss(str);
+ iss.imbue(loc);
+ boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
+ iss >> ptime;
+ if (ptime.is_not_a_date_time())
+ return 0;
+ return (ptime - epoch).total_seconds();
+}
+
+std::string static EncodeDumpString(const std::string &str) {
+ std::stringstream ret;
+ BOOST_FOREACH(unsigned char c, str) {
+ if (c <= 32 || c >= 128 || c == '%') {
+ ret << '%' << HexStr(&c, &c + 1);
+ } else {
+ ret << c;
+ }
+ }
+ return ret.str();
+}
+
+std::string DecodeDumpString(const std::string &str) {
+ std::stringstream ret;
+ for (unsigned int pos = 0; pos < str.length(); pos++) {
+ unsigned char c = str[pos];
+ if (c == '%' && pos+2 < str.length()) {
+ c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
+ ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
+ pos += 2;
+ }
+ ret << c;
}
-};
+ return ret.str();
+}
Value importprivkey(const Array& params, bool fHelp)
{
@@ -63,6 +96,10 @@ Value importprivkey(const Array& params, bool fHelp)
pwalletMain->MarkDirty();
pwalletMain->SetAddressBookName(vchAddress, strLabel);
+ // Don't throw error in case a key is already there
+ if (pwalletMain->HaveKey(vchAddress))
+ return Value::null;
+
if (!pwalletMain->AddKeyPubKey(key, pubkey))
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
@@ -75,6 +112,86 @@ Value importprivkey(const Array& params, bool fHelp)
return Value::null;
}
+Value importwallet(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "importwallet <filename>\n"
+ "Imports keys from a wallet dump file (see dumpwallet).");
+
+ EnsureWalletIsUnlocked();
+
+ ifstream file;
+ file.open(params[0].get_str().c_str());
+ if (!file.is_open())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
+
+ int64 nTimeBegin = pindexBest->nTime;
+
+ bool fGood = true;
+
+ while (file.good()) {
+ std::string line;
+ std::getline(file, line);
+ if (line.empty() || line[0] == '#')
+ continue;
+
+ std::vector<std::string> vstr;
+ boost::split(vstr, line, boost::is_any_of(" "));
+ if (vstr.size() < 2)
+ continue;
+ CBitcoinSecret vchSecret;
+ if (!vchSecret.SetString(vstr[0]))
+ continue;
+ CKey key = vchSecret.GetKey();
+ CPubKey pubkey = key.GetPubKey();
+ CKeyID keyid = pubkey.GetID();
+ if (pwalletMain->HaveKey(keyid)) {
+ printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str());
+ continue;
+ }
+ int64 nTime = DecodeDumpTime(vstr[1]);
+ std::string strLabel;
+ bool fLabel = true;
+ for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
+ if (boost::algorithm::starts_with(vstr[nStr], "#"))
+ break;
+ if (vstr[nStr] == "change=1")
+ fLabel = false;
+ if (vstr[nStr] == "reserve=1")
+ fLabel = false;
+ if (boost::algorithm::starts_with(vstr[nStr], "label=")) {
+ strLabel = DecodeDumpString(vstr[nStr].substr(6));
+ fLabel = true;
+ }
+ }
+ printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str());
+ if (!pwalletMain->AddKeyPubKey(key, pubkey)) {
+ fGood = false;
+ continue;
+ }
+ pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime;
+ if (fLabel)
+ pwalletMain->SetAddressBookName(keyid, strLabel);
+ nTimeBegin = std::min(nTimeBegin, nTime);
+ }
+ file.close();
+
+ CBlockIndex *pindex = pindexBest;
+ while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
+ pindex = pindex->pprev;
+
+ printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1);
+ pwalletMain->ScanForWalletTransactions(pindex);
+ pwalletMain->ReacceptWalletTransactions();
+ pwalletMain->MarkDirty();
+
+ if (!fGood)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
+
+ return Value::null;
+}
+
Value dumpprivkey(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
@@ -82,6 +199,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
"dumpprivkey <bitcoinaddress>\n"
"Reveals the private key corresponding to <bitcoinaddress>.");
+ EnsureWalletIsUnlocked();
+
string strAddress = params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
@@ -94,3 +213,58 @@ Value dumpprivkey(const Array& params, bool fHelp)
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
return CBitcoinSecret(vchSecret).ToString();
}
+
+
+Value dumpwallet(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "dumpwallet <filename>\n"
+ "Dumps all wallet keys in a human-readable format.");
+
+ EnsureWalletIsUnlocked();
+
+ ofstream file;
+ file.open(params[0].get_str().c_str());
+ if (!file.is_open())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
+
+ std::map<CKeyID, int64> mapKeyBirth;
+ std::set<CKeyID> setKeyPool;
+ pwalletMain->GetKeyBirthTimes(mapKeyBirth);
+ pwalletMain->GetAllReserveKeys(setKeyPool);
+
+ // sort time/key pairs
+ std::vector<std::pair<int64, CKeyID> > vKeyBirth;
+ for (std::map<CKeyID, int64>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) {
+ vKeyBirth.push_back(std::make_pair(it->second, it->first));
+ }
+ mapKeyBirth.clear();
+ std::sort(vKeyBirth.begin(), vKeyBirth.end());
+
+ // produce output
+ file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str());
+ file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str());
+ file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str());
+ file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str());
+ file << "\n";
+ for (std::vector<std::pair<int64, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
+ const CKeyID &keyid = it->second;
+ std::string strTime = EncodeDumpTime(it->first);
+ std::string strAddr = CBitcoinAddress(keyid).ToString();
+ CKey key;
+ if (pwalletMain->GetKey(keyid, key)) {
+ if (pwalletMain->mapAddressBook.count(keyid)) {
+ file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), EncodeDumpString(pwalletMain->mapAddressBook[keyid]).c_str(), strAddr.c_str());
+ } else if (setKeyPool.count(keyid)) {
+ file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), strAddr.c_str());
+ } else {
+ file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), strAddr.c_str());
+ }
+ }
+ }
+ file << "\n";
+ file << "# End of dump\n";
+ file.close();
+ return Value::null;
+}
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index d0b0a70be4..a70c0958df 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -4,7 +4,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chainparams.h"
-#include "main.h"
#include "db.h"
#include "init.h"
#include "bitcoinrpc.h"
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 61cb4e390e..f08688d386 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -9,7 +9,6 @@
#include "bitcoinrpc.h"
#include "db.h"
#include "init.h"
-#include "main.h"
#include "net.h"
#include "wallet.h"
diff --git a/src/script.cpp b/src/script.cpp
index cf6eeaf392..14fe80e207 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -1474,6 +1474,42 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
return true;
}
+class CAffectedKeysVisitor : public boost::static_visitor<void> {
+private:
+ const CKeyStore &keystore;
+ std::vector<CKeyID> &vKeys;
+
+public:
+ CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {}
+
+ void Process(const CScript &script) {
+ txnouttype type;
+ std::vector<CTxDestination> vDest;
+ int nRequired;
+ if (ExtractDestinations(script, type, vDest, nRequired)) {
+ BOOST_FOREACH(const CTxDestination &dest, vDest)
+ boost::apply_visitor(*this, dest);
+ }
+ }
+
+ void operator()(const CKeyID &keyId) {
+ if (keystore.HaveKey(keyId))
+ vKeys.push_back(keyId);
+ }
+
+ void operator()(const CScriptID &scriptId) {
+ CScript script;
+ if (keystore.GetCScript(scriptId, script))
+ Process(script);
+ }
+
+ void operator()(const CNoDestination &none) {}
+};
+
+void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) {
+ CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey);
+}
+
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
unsigned int flags, int nHashType)
{
diff --git a/src/script.h b/src/script.h
index f963467c94..03afe8b652 100644
--- a/src/script.h
+++ b/src/script.h
@@ -674,6 +674,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
bool IsStandard(const CScript& scriptPubKey);
bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
bool IsMine(const CKeyStore& keystore, const CTxDestination &dest);
+void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
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/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index d626f9a6f4..5675c40e76 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15)
// After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW
- BOOST_CHECK(forkingBlock.CheckBlock(state, false, false));
+ BOOST_CHECK(CheckBlock(forkingBlock, state, false, false));
}
SetMockTime(0);
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/util.h b/src/util.h
index 86a38ad331..bee2749c16 100644
--- a/src/util.h
+++ b/src/util.h
@@ -527,7 +527,7 @@ inline uint32_t ByteReverse(uint32_t value)
// Standard wrapper for do-something-forever thread functions.
// "Forever" really means until the thread is interrupted.
// Use it like:
-// new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 10000));
+// new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 900000));
// or maybe:
// boost::function<void()> f = boost::bind(&FunctionWithArg, argument);
// threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds));
@@ -540,8 +540,8 @@ template <typename Callable> void LoopForever(const char* name, Callable func,
{
while (1)
{
- func();
MilliSleep(msecs);
+ func();
}
}
catch (boost::thread_interrupted)
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/wallet.cpp b/src/wallet.cpp
index a205d52b55..488787f967 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -804,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
}
CBlock block;
- block.ReadFromDisk(pindex);
+ ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
@@ -1846,7 +1846,7 @@ void CReserveKey::ReturnKey()
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress)
+void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
setAddress.clear();
@@ -1908,3 +1908,53 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
}
}
+void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
+ mapKeyBirth.clear();
+
+ // get birth times for keys with metadata
+ for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
+ if (it->second.nCreateTime)
+ mapKeyBirth[it->first] = it->second.nCreateTime;
+
+ // map in which we'll infer heights of other keys
+ CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
+ std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
+ std::set<CKeyID> setKeys;
+ GetKeys(setKeys);
+ BOOST_FOREACH(const CKeyID &keyid, setKeys) {
+ if (mapKeyBirth.count(keyid) == 0)
+ mapKeyFirstBlock[keyid] = pindexMax;
+ }
+ setKeys.clear();
+
+ // if there are no such keys, we're done
+ if (mapKeyFirstBlock.empty())
+ return;
+
+ // find first block that affects those keys, if there are any left
+ std::vector<CKeyID> vAffected;
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
+ // iterate over all wallet transactions...
+ const CWalletTx &wtx = (*it).second;
+ std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
+ if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
+ // ... which are already in a block
+ int nHeight = blit->second->nHeight;
+ BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
+ // iterate over all their outputs
+ ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected);
+ BOOST_FOREACH(const CKeyID &keyid, vAffected) {
+ // ... and all their affected keys
+ std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
+ if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
+ rit->second = blit->second;
+ }
+ vAffected.clear();
+ }
+ }
+ }
+
+ // Extract block timestamps for those keys
+ for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
+ mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
+}
diff --git a/src/wallet.h b/src/wallet.h
index 48bd511971..36b3608fb0 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -159,6 +159,8 @@ public:
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
+ void GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const;
+
/** Increment the next transaction order id
@return next transaction order id
*/
@@ -200,7 +202,7 @@ public:
void ReturnKey(int64 nIndex);
bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true);
int64 GetOldestKeyPoolTime();
- void GetAllReserveKeys(std::set<CKeyID>& setAddress);
+ void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, int64> GetAddressBalances();
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index bf23357f79..702e219a5b 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -365,7 +365,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{
int64 nIndex;
ssKey >> nIndex;
+ CKeyPool keypool;
+ ssValue >> keypool;
pwallet->setKeyPool.insert(nIndex);
+
+ // If no metadata exists yet, create a default with the pool key's
+ // creation time. Note that this may be overwritten by actually
+ // stored metadata for that key later, which is fine.
+ CKeyID keyid = keypool.vchPubKey.GetID();
+ if (pwallet->mapKeyMetadata.count(keyid) == 0)
+ pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
}
else if (strType == "version")
{