aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitcoinrpc.cpp5
-rw-r--r--src/bitcoinrpc.h2
-rw-r--r--src/checkpoints.cpp76
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/checkqueue.h4
-rw-r--r--src/clientversion.h6
-rw-r--r--src/init.cpp87
-rw-r--r--src/leveldb.cpp16
-rw-r--r--src/leveldb.h23
-rw-r--r--src/main.cpp526
-rw-r--r--src/main.h112
-rw-r--r--src/makefile.linux-mingw15
-rw-r--r--src/makefile.mingw15
-rw-r--r--src/makefile.osx7
-rw-r--r--src/makefile.unix8
-rw-r--r--src/net.cpp256
-rw-r--r--src/net.h3
-rw-r--r--src/noui.cpp4
-rw-r--r--src/qt/aboutdialog.cpp8
-rw-r--r--src/qt/aboutdialog.h1
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/qt/bitcoingui.cpp90
-rw-r--r--src/qt/bitcoingui.h5
-rw-r--r--src/qt/bitcoinstrings.cpp15
-rw-r--r--src/qt/clientmodel.cpp11
-rw-r--r--src/qt/clientmodel.h1
-rw-r--r--src/qt/forms/aboutdialog.ui5
-rw-r--r--src/qt/guiconstants.h2
-rw-r--r--src/qt/locale/bitcoin_en.ts178
-rw-r--r--src/qt/notificator.cpp2
-rw-r--r--src/rpcmining.cpp7
-rw-r--r--src/rpcnet.cpp134
-rw-r--r--src/rpcrawtransaction.cpp21
-rw-r--r--src/rpcwallet.cpp1
-rw-r--r--src/test/miner_tests.cpp4
-rw-r--r--src/test/test_bitcoin.cpp2
-rw-r--r--src/test/transaction_tests.cpp12
-rw-r--r--src/test/util_tests.cpp62
-rw-r--r--src/txdb.cpp4
-rw-r--r--src/txdb.h4
-rw-r--r--src/ui_interface.h2
-rw-r--r--src/util.cpp80
-rw-r--r--src/util.h28
-rw-r--r--src/wallet.cpp27
-rw-r--r--src/walletdb.cpp3
45 files changed, 1268 insertions, 616 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index a1e39d7506..230a248422 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -201,6 +201,8 @@ static const CRPCCommand vRPCCommands[] =
{ "getblockcount", &getblockcount, true, false },
{ "getconnectioncount", &getconnectioncount, true, false },
{ "getpeerinfo", &getpeerinfo, true, false },
+ { "addnode", &addnode, true, true },
+ { "getaddednodeinfo", &getaddednodeinfo, true, true },
{ "getdifficulty", &getdifficulty, true, false },
{ "getgenerate", &getgenerate, true, false },
{ "setgenerate", &setgenerate, true, false },
@@ -244,7 +246,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getblocktemplate", &getblocktemplate, true, false },
{ "submitblock", &submitblock, false, false },
{ "listsinceblock", &listsinceblock, false, false },
- { "dumpprivkey", &dumpprivkey, false, false },
+ { "dumpprivkey", &dumpprivkey, true, false },
{ "importprivkey", &importprivkey, false, false },
{ "listunspent", &listunspent, false, false },
{ "getrawtransaction", &getrawtransaction, false, false },
@@ -1179,6 +1181,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
// Special case non-string parameter types
//
if (strMethod == "stop" && n > 0) ConvertTo<bool>(params[0]);
+ if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h
index 44050ae1bb..36bfbe3eef 100644
--- a/src/bitcoinrpc.h
+++ b/src/bitcoinrpc.h
@@ -132,6 +132,8 @@ extern void EnsureWalletIsUnlocked();
extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp
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);
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 4d2096ef07..9b11f0b351 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -14,13 +14,25 @@ namespace Checkpoints
{
typedef std::map<int, uint256> MapCheckpoints;
- //
+ // How many times we expect transactions after the last checkpoint to
+ // be slower. This number is conservative. On multi-core CPUs with
+ // parallel signature checking enabled, this number is way too high.
+ // We prefer a progressbar that's faster at the end than the other
+ // way around, though.
+ static const double fSigcheckVerificationFactor = 15.0;
+
+ struct CCheckpointData {
+ const MapCheckpoints *mapCheckpoints;
+ int64 nTimeLastCheckpoint;
+ int64 nTransactionsLastCheckpoint;
+ double fTransactionsPerDay;
+ };
+
// What makes a good checkpoint block?
// + Is surrounded by blocks with reasonable timestamps
// (no blocks before with a timestamp after, none after with
// timestamp before)
// + Contains no strange transactions
- //
static MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
@@ -31,31 +43,83 @@ namespace Checkpoints
(168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
(193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
(210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
+ (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
;
+ static const CCheckpointData data = {
+ &mapCheckpoints,
+ 1357902690, // * UNIX timestamp of last checkpoint block
+ 11011160, // * total number of transactions between genesis and last checkpoint
+ // (the tx=... number in the SetBestChain debug.log lines)
+ 50000.0 // * estimated number of transactions per day after checkpoint
+ };
- static MapCheckpoints mapCheckpointsTestnet =
+ static MapCheckpoints mapCheckpointsTestnet =
boost::assign::map_list_of
( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
;
+ static const CCheckpointData dataTestnet = {
+ &mapCheckpointsTestnet,
+ 1338180505,
+ 16341,
+ 300
+ };
+
+ const CCheckpointData &Checkpoints() {
+ if (fTestNet)
+ return dataTestnet;
+ else
+ return data;
+ }
bool CheckBlock(int nHeight, const uint256& hash)
{
if (!GetBoolArg("-checkpoints", true))
return true;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return true;
return hash == i->second;
}
+ // Guess how far we are in the verification process at the given block index
+ double GuessVerificationProgress(CBlockIndex *pindex) {
+ if (pindex==NULL)
+ return 0.0;
+
+ int64 nNow = time(NULL);
+
+ double fWorkBefore = 0.0; // Amount of work done before pindex
+ double fWorkAfter = 0.0; // Amount of work left after pindex (estimated)
+ // Work is defined as: 1.0 per transaction before the last checkoint, and
+ // fSigcheckVerificationFactor per transaction after.
+
+ const CCheckpointData &data = Checkpoints();
+
+ if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) {
+ double nCheapBefore = pindex->nChainTx;
+ double nCheapAfter = data.nTransactionsLastCheckpoint - pindex->nChainTx;
+ double nExpensiveAfter = (nNow - data.nTimeLastCheckpoint)/86400.0*data.fTransactionsPerDay;
+ fWorkBefore = nCheapBefore;
+ fWorkAfter = nCheapAfter + nExpensiveAfter*fSigcheckVerificationFactor;
+ } else {
+ double nCheapBefore = data.nTransactionsLastCheckpoint;
+ double nExpensiveBefore = pindex->nChainTx - data.nTransactionsLastCheckpoint;
+ double nExpensiveAfter = (nNow - pindex->nTime)/86400.0*data.fTransactionsPerDay;
+ fWorkBefore = nCheapBefore + nExpensiveBefore*fSigcheckVerificationFactor;
+ fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor;
+ }
+
+ return fWorkBefore / (fWorkBefore + fWorkAfter);
+ }
+
int GetTotalBlocksEstimate()
{
if (!GetBoolArg("-checkpoints", true))
return 0;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
return checkpoints.rbegin()->first;
}
@@ -65,7 +129,7 @@ namespace Checkpoints
if (!GetBoolArg("-checkpoints", true))
return NULL;
- MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+ const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints;
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 70e936564c..dcfb44e10f 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -22,6 +22,8 @@ namespace Checkpoints
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
+
+ double GuessVerificationProgress(CBlockIndex *pindex);
}
#endif
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 36141dd74b..12dde36fe7 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -163,6 +163,10 @@ public:
condQuit.wait(lock);
}
+ ~CCheckQueue() {
+ Quit();
+ }
+
friend class CCheckQueueControl<T>;
};
diff --git a/src/clientversion.h b/src/clientversion.h
index 24355d1a54..44cda07b81 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -7,12 +7,12 @@
// These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
-#define CLIENT_VERSION_MINOR 7
-#define CLIENT_VERSION_REVISION 99
+#define CLIENT_VERSION_MINOR 8
+#define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 0
// Set to true for release, false for prerelease or test build
-#define CLIENT_VERSION_IS_RELEASE false
+#define CLIENT_VERSION_IS_RELEASE true
// Converts the parameter X to a string after macro replacement on X has been performed.
// Don't merge these into one macro!
diff --git a/src/init.cpp b/src/init.cpp
index 7285e7c0d5..64f91a349f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -82,6 +82,7 @@ void Shutdown(void* parg)
if (fFirstThread)
{
fShutdown = true;
+ fRequestShutdown = true;
nTransactionsUpdated++;
bitdb.Flush(false);
{
@@ -187,9 +188,9 @@ bool AppInit(int argc, char* argv[])
fRet = AppInit2();
}
catch (std::exception& e) {
- PrintException(&e, "AppInit()");
+ PrintExceptionContinue(&e, "AppInit()");
} catch (...) {
- PrintException(NULL, "AppInit()");
+ PrintExceptionContinue(NULL, "AppInit()");
}
if (!fRet)
Shutdown(NULL);
@@ -299,11 +300,12 @@ std::string HelpMessage()
" -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
+ " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
" -upgradewallet " + _("Upgrade wallet to latest format") + "\n" +
" -keypool=<n> " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" +
" -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" +
- " -checkblocks=<n> " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
+ " -checkblocks=<n> " + _("How many blocks to check at startup (default: 288, 0 = all)") + "\n" +
" -checklevel=<n> " + _("How thorough the block verification is (0-4, default: 3)") + "\n" +
" -txindex " + _("Maintain a full transaction index (default: 0)") + "\n" +
" -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + "\n" +
@@ -365,6 +367,8 @@ void ThreadImport(void *data) {
pblocktree->WriteReindexing(false);
fReindex = false;
printf("Reindexing finished\n");
+ // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
+ InitBlockIndex();
}
}
@@ -789,23 +793,69 @@ bool AppInit2()
nTotalCache -= nCoinDBCache;
nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes
- uiInterface.InitMessage(_("Loading block index..."));
+ bool fLoaded = false;
+ while (!fLoaded) {
+ bool fReset = fReindex;
+ std::string strLoadError;
- nStart = GetTimeMillis();
- pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
- pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
-
- if (fReindex)
- pblocktree->WriteReindexing(true);
-
- if (!LoadBlockIndex())
- return InitError(_("Error loading block database"));
+ uiInterface.InitMessage(_("Loading block index..."));
- uiInterface.InitMessage(_("Verifying block database integrity..."));
+ nStart = GetTimeMillis();
+ do {
+ try {
+ UnloadBlockIndex();
+ delete pcoinsTip;
+ delete pcoinsdbview;
+ delete pblocktree;
+
+ pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex);
+ pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
+ pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+
+ if (fReindex)
+ pblocktree->WriteReindexing(true);
+
+ if (!LoadBlockIndex()) {
+ strLoadError = _("Error loading block database");
+ break;
+ }
+
+ // Initialize the block index (no-op if non-empty database was already loaded)
+ if (!InitBlockIndex()) {
+ strLoadError = _("Error initializing block database");
+ break;
+ }
+
+ uiInterface.InitMessage(_("Verifying database..."));
+ if (!VerifyDB()) {
+ strLoadError = _("Corrupted block database detected");
+ break;
+ }
+ } catch(std::exception &e) {
+ strLoadError = _("Error opening block database");
+ break;
+ }
- if (!VerifyDB())
- return InitError(_("Corrupted block database detected. Please restart the client with -reindex."));
+ fLoaded = true;
+ } while(false);
+
+ if (!fLoaded) {
+ // first suggest a reindex
+ if (!fReset) {
+ bool fRet = uiInterface.ThreadSafeMessageBox(
+ strLoadError + ".\n" + _("Do you want to rebuild the block database now?"),
+ "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
+ if (fRet) {
+ fReindex = true;
+ fRequestShutdown = false;
+ } else {
+ return false;
+ }
+ } else {
+ return InitError(strLoadError);
+ }
+ }
+ }
if (mapArgs.count("-txindex") && fTxIndex != GetBoolArg("-txindex", false))
return InitError(_("You need to rebuild the databases using -reindex to change -txindex"));
@@ -936,7 +986,8 @@ bool AppInit2()
// scan for better chains in the block chain database, that are not yet connected in the active best chain
uiInterface.InitMessage(_("Importing blocks from block database..."));
- if (!ConnectBestBlock())
+ CValidationState state;
+ if (!ConnectBestBlock(state))
strErrors << "Failed to connect best block";
CImportData *pimport = new CImportData();
diff --git a/src/leveldb.cpp b/src/leveldb.cpp
index 9e2f32a171..b41764f51f 100644
--- a/src/leveldb.cpp
+++ b/src/leveldb.cpp
@@ -12,6 +12,18 @@
#include <boost/filesystem.hpp>
+void HandleError(const leveldb::Status &status) throw(leveldb_error) {
+ if (status.ok())
+ return;
+ if (status.IsCorruption())
+ throw leveldb_error("Database corrupted");
+ if (status.IsIOError())
+ throw leveldb_error("Database I/O error");
+ if (status.IsNotFound())
+ throw leveldb_error("Database entry missing");
+ throw leveldb_error("Unknown database error");
+}
+
static leveldb::Options GetOptions(size_t nCacheSize) {
leveldb::Options options;
options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
@@ -57,12 +69,12 @@ CLevelDB::~CLevelDB() {
options.env = NULL;
}
-bool CLevelDB::WriteBatch(CLevelDBBatch &batch, bool fSync) {
+bool CLevelDB::WriteBatch(CLevelDBBatch &batch, bool fSync) throw(leveldb_error) {
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
if (!status.ok()) {
printf("LevelDB write failure: %s\n", status.ToString().c_str());
+ HandleError(status);
return false;
}
return true;
}
-
diff --git a/src/leveldb.h b/src/leveldb.h
index 0b83432072..79262edbb5 100644
--- a/src/leveldb.h
+++ b/src/leveldb.h
@@ -11,6 +11,14 @@
#include <boost/filesystem/path.hpp>
+class leveldb_error : public std::runtime_error
+{
+public:
+ leveldb_error(const std::string &msg) : std::runtime_error(msg) {}
+};
+
+void HandleError(const leveldb::Status &status) throw(leveldb_error);
+
// Batch of changes queued to be written to a CLevelDB
class CLevelDBBatch
{
@@ -72,7 +80,7 @@ public:
CLevelDB(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
~CLevelDB();
- template<typename K, typename V> bool Read(const K& key, V& value) {
+ template<typename K, typename V> bool Read(const K& key, V& value) throw(leveldb_error) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
@@ -84,6 +92,7 @@ public:
if (status.IsNotFound())
return false;
printf("LevelDB read failure: %s\n", status.ToString().c_str());
+ HandleError(status);
}
try {
CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
@@ -94,13 +103,13 @@ public:
return true;
}
- template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) {
+ template<typename K, typename V> bool Write(const K& key, const V& value, bool fSync = false) throw(leveldb_error) {
CLevelDBBatch batch;
batch.Write(key, value);
return WriteBatch(batch, fSync);
}
- template<typename K> bool Exists(const K& key) {
+ template<typename K> bool Exists(const K& key) throw(leveldb_error) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
@@ -112,24 +121,25 @@ public:
if (status.IsNotFound())
return false;
printf("LevelDB read failure: %s\n", status.ToString().c_str());
+ HandleError(status);
}
return true;
}
- template<typename K> bool Erase(const K& key, bool fSync = false) {
+ template<typename K> bool Erase(const K& key, bool fSync = false) throw(leveldb_error) {
CLevelDBBatch batch;
batch.Erase(key);
return WriteBatch(batch, fSync);
}
- bool WriteBatch(CLevelDBBatch &batch, bool fSync = false);
+ bool WriteBatch(CLevelDBBatch &batch, bool fSync = false) throw(leveldb_error);
// not available for LevelDB; provide for compatibility with BDB
bool Flush() {
return true;
}
- bool Sync() {
+ bool Sync() throw(leveldb_error) {
CLevelDBBatch batch;
return WriteBatch(batch, true);
}
@@ -141,4 +151,3 @@ public:
};
#endif // BITCOIN_LEVELDB_H
- \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 212240ec22..794913d282 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -93,15 +93,6 @@ void UnregisterWallet(CWallet* pwalletIn)
}
}
-// check whether the passed transaction is from us
-bool static IsFromMe(CTransaction& tx)
-{
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- if (pwallet->IsFromMe(tx))
- return true;
- return false;
-}
-
// get the wallet transaction with the given hash (if it exists)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
{
@@ -369,6 +360,17 @@ bool CTransaction::IsStandard() const
if (nVersion > CTransaction::CURRENT_VERSION)
return false;
+ if (!IsFinal())
+ return false;
+
+ // Extremely large transactions with lots of inputs can cost the network
+ // almost as much to process as they cost the sender in fees, because
+ // computing signature hashes is O(ninputs*txsize). Limiting transactions
+ // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
+ unsigned int sz = this->GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
+ if (sz >= MAX_STANDARD_TX_SIZE)
+ return false;
+
BOOST_FOREACH(const CTxIn& txin, vin)
{
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
@@ -522,28 +524,28 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
-bool CTransaction::CheckTransaction() const
+bool CTransaction::CheckTransaction(CValidationState &state) const
{
// Basic checks that don't depend on any context
if (vin.empty())
- return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
+ return state.DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
if (vout.empty())
- return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
+ return state.DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
- return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
+ return state.DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
if (txout.nValue < 0)
- return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
+ return state.DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
if (txout.nValue > MAX_MONEY)
- return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
+ return state.DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
- return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
+ return state.DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
}
// Check for duplicate inputs
@@ -551,20 +553,20 @@ bool CTransaction::CheckTransaction() const
BOOST_FOREACH(const CTxIn& txin, vin)
{
if (vInOutPoints.count(txin.prevout))
- return false;
+ return state.DoS(100, error("CTransaction::CheckTransaction() : duplicate inputs"));
vInOutPoints.insert(txin.prevout);
}
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
+ return state.DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
}
else
{
BOOST_FOREACH(const CTxIn& txin, vin)
if (txin.prevout.IsNull())
- return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
+ return state.DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
}
return true;
@@ -631,18 +633,18 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
}
-bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
+bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree,
bool* pfMissingInputs)
{
if (pfMissingInputs)
*pfMissingInputs = false;
- if (!tx.CheckTransaction())
+ if (!tx.CheckTransaction(state))
return error("CTxMemPool::accept() : CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
- return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
+ return state.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
// To help v0.1.5 clients who would see it as a negative number
if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
@@ -715,7 +717,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
// are the actual inputs available?
if (!tx.HaveInputs(view))
- return error("CTxMemPool::accept() : inputs already spent");
+ return state.Invalid(error("CTxMemPool::accept() : inputs already spent"));
// Bring the best block into scope
view.GetBestBlock();
@@ -737,7 +739,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
// Don't accept it if it can't get into a block
int64 txMinFee = tx.GetMinFee(1000, true, GMF_RELAY);
- if (nFees < txMinFee)
+ if (fLimitFree && nFees < txMinFee)
return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
hash.ToString().c_str(),
nFees, txMinFee);
@@ -745,30 +747,29 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (nFees < MIN_RELAY_TX_FEE)
+ if (fLimitFree && nFees < MIN_RELAY_TX_FEE)
{
- static CCriticalSection cs;
static double dFreeCount;
static int64 nLastTime;
int64 nNow = GetTime();
- {
- // Use an exponentially decaying ~10-minute window:
- dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
- nLastTime = nNow;
- // -limitfreerelay unit is thousand-bytes-per-minute
- // At default rate it would take over a month to fill 1GB
- if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
- return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
- if (fDebug)
- printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
- dFreeCount += nSize;
- }
+ LOCK(cs);
+
+ // Use an exponentially decaying ~10-minute window:
+ dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
+ nLastTime = nNow;
+ // -limitfreerelay unit is thousand-bytes-per-minute
+ // At default rate it would take over a month to fill 1GB
+ if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
+ return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
+ if (fDebug)
+ printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
+ dFreeCount += nSize;
}
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!tx.CheckInputs(view, true, SCRIPT_VERIFY_P2SH))
+ if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH))
{
return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
}
@@ -797,9 +798,13 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
return true;
}
-bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
+bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs)
{
- return mempool.accept(*this, fCheckInputs, pfMissingInputs);
+ try {
+ return mempool.accept(state, *this, fCheckInputs, fLimitFree, pfMissingInputs);
+ } catch(std::runtime_error &e) {
+ return state.Abort(_("System error: ") + e.what());
+ }
}
bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
@@ -910,9 +915,10 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs)
+bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree)
{
- return CTransaction::AcceptToMemoryPool(fCheckInputs);
+ CValidationState state;
+ return CTransaction::AcceptToMemoryPool(state, fCheckInputs, fLimitFree);
}
@@ -928,10 +934,10 @@ bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
{
uint256 hash = tx.GetHash();
if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash))
- tx.AcceptToMemoryPool(fCheckInputs);
+ tx.AcceptToMemoryPool(fCheckInputs, false);
}
}
- return AcceptToMemoryPool(fCheckInputs);
+ return AcceptToMemoryPool(fCheckInputs, false);
}
return false;
}
@@ -1208,11 +1214,13 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
setBlockIndexValid.erase(pindex);
InvalidChainFound(pindex);
- if (pindex->pnext)
- ConnectBestBlock(); // reorganise away from the failed block
+ if (pindex->pnext) {
+ CValidationState stateDummy;
+ ConnectBestBlock(stateDummy); // reorganise away from the failed block
+ }
}
-bool ConnectBestBlock() {
+bool ConnectBestBlock(CValidationState &state) {
do {
CBlockIndex *pindexNewBest;
@@ -1251,8 +1259,12 @@ bool ConnectBestBlock() {
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
if (fRequestShutdown)
break;
- if (!SetBestChain(pindexSwitch))
- return false;
+ try {
+ if (!SetBestChain(state, pindexSwitch))
+ return false;
+ } catch(std::runtime_error &e) {
+ return state.Abort(_("System error: ") + e.what());
+ }
}
return true;
}
@@ -1314,22 +1326,20 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const
return nSigOps;
}
-bool CTransaction::UpdateCoins(CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const
+bool CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const
{
// mark inputs spent
if (!IsCoinBase()) {
BOOST_FOREACH(const CTxIn &txin, vin) {
CCoins &coins = inputs.GetCoins(txin.prevout.hash);
CTxInUndo undo;
- if (!coins.Spend(txin.prevout, undo))
- return error("UpdateCoins() : cannot spend input");
+ assert(coins.Spend(txin.prevout, undo));
txundo.vprevout.push_back(undo);
}
}
// add outputs
- if (!inputs.SetCoins(txhash, CCoins(*this, nHeight)))
- return error("UpdateCoins() : cannot update output");
+ assert(inputs.SetCoins(txhash, CCoins(*this, nHeight)));
return true;
}
@@ -1367,7 +1377,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
}
-bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks) const
+bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks) const
{
if (!IsCoinBase())
{
@@ -1377,7 +1387,7 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!HaveInputs(inputs))
- return error("CheckInputs() : %s inputs unavailable", GetHash().ToString().substr(0,10).c_str());
+ return state.Invalid(error("CheckInputs() : %s inputs unavailable", GetHash().ToString().substr(0,10).c_str()));
// While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks.
@@ -1392,26 +1402,26 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
// If prev is coinbase, check that it's matured
if (coins.IsCoinBase()) {
if (nSpendHeight - coins.nHeight < COINBASE_MATURITY)
- return error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight);
+ return state.Invalid(error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins.nHeight));
}
// Check for negative or overflow input values
nValueIn += coins.vout[prevout.n].nValue;
if (!MoneyRange(coins.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return DoS(100, error("CheckInputs() : txin values out of range"));
+ return state.DoS(100, error("CheckInputs() : txin values out of range"));
}
if (nValueIn < GetValueOut())
- return DoS(100, error("ChecktInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
+ return state.DoS(100, error("CheckInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
- return DoS(100, error("CheckInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
+ return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
nFees += nTxFee;
if (!MoneyRange(nFees))
- return DoS(100, error("CheckInputs() : nFees out of range"));
+ return state.DoS(100, error("CheckInputs() : nFees out of range"));
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
@@ -1431,7 +1441,7 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
} else if (!check())
- return DoS(100,false);
+ return state.DoS(100,false);
}
}
}
@@ -1440,56 +1450,9 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
}
-bool CTransaction::ClientCheckInputs() const
-{
- if (IsCoinBase())
- return false;
-
- // Take over previous transactions' spent pointers
- {
- LOCK(mempool.cs);
- int64 nValueIn = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- // Get prev tx from single transactions in memory
- COutPoint prevout = vin[i].prevout;
- if (!mempool.exists(prevout.hash))
- return false;
- CTransaction& txPrev = mempool.lookup(prevout.hash);
-
- if (prevout.n >= txPrev.vout.size())
- return false;
-
- // Verify signature
- if (!VerifySignature(CCoins(txPrev, -1), *this, i, SCRIPT_VERIFY_P2SH, 0))
- return error("ConnectInputs() : VerifySignature failed");
-
- ///// this is redundant with the mempool.mapNextTx stuff,
- ///// not sure which I want to get rid of
- ///// this has to go away now that posNext is gone
- // // Check for conflicts
- // if (!txPrev.vout[prevout.n].posNext.IsNull())
- // return error("ConnectInputs() : prev tx already used");
- //
- // // Flag outpoints as used
- // txPrev.vout[prevout.n].posNext = posThisTx;
-
- nValueIn += txPrev.vout[prevout.n].nValue;
-
- if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return error("ClientConnectInputs() : txin values out of range");
- }
- if (GetValueOut() > nValueIn)
- return false;
- }
-
- return true;
-}
-
-
-bool CBlock::DisconnectBlock(CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
+bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
{
assert(pindex == view.GetBestBlock());
@@ -1571,7 +1534,7 @@ bool CBlock::DisconnectBlock(CBlockIndex *pindex, CCoinsViewCache &view, bool *p
}
}
-void static FlushBlockFile()
+void static FlushBlockFile(bool fFinalize = false)
{
LOCK(cs_LastBlockFile);
@@ -1579,18 +1542,22 @@ void static FlushBlockFile()
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
+ if (fFinalize)
+ TruncateFile(fileOld, infoLastBlockFile.nSize);
FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
+ if (fFinalize)
+ TruncateFile(fileOld, infoLastBlockFile.nUndoSize);
FileCommit(fileOld);
fclose(fileOld);
}
}
-bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
+bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
@@ -1605,10 +1572,10 @@ void ThreadScriptCheckQuit() {
scriptcheckqueue.Quit();
}
-bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck)
+bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck)
{
// Check it again in case a previous version let a bad block in
- if (!CheckBlock(!fJustCheck, !fJustCheck))
+ if (!CheckBlock(state, !fJustCheck, !fJustCheck))
return false;
// verify that the view's current state corresponds to the previous block
@@ -1643,7 +1610,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
for (unsigned int i=0; i<vtx.size(); i++) {
uint256 hash = GetTxHash(i);
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
- return error("ConnectBlock() : tried to overwrite transaction");
+ return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
}
}
@@ -1673,12 +1640,12 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
nInputs += tx.vin.size();
nSigOps += tx.GetLegacySigOpCount();
if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("ConnectBlock() : too many sigops"));
+ return state.DoS(100, error("ConnectBlock() : too many sigops"));
if (!tx.IsCoinBase())
{
if (!tx.HaveInputs(view))
- return DoS(100, error("ConnectBlock() : inputs missing/spent"));
+ return state.DoS(100, error("ConnectBlock() : inputs missing/spent"));
if (fStrictPayToScriptHash)
{
@@ -1687,19 +1654,19 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
// an incredibly-expensive-to-validate block.
nSigOps += tx.GetP2SHSigOpCount(view);
if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("ConnectBlock() : too many sigops"));
+ return state.DoS(100, error("ConnectBlock() : too many sigops"));
}
nFees += tx.GetValueIn(view)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
- if (!tx.CheckInputs(view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
+ if (!tx.CheckInputs(state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
CTxUndo txundo;
- if (!tx.UpdateCoins(view, txundo, pindex->nHeight, GetTxHash(i)))
+ if (!tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i)))
return error("ConnectBlock() : UpdateInputs failed");
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
@@ -1712,10 +1679,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
- return error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees));
+ return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)));
if (!control.Wait())
- return DoS(100, false);
+ return state.DoS(100, false);
int64 nTime2 = GetTimeMicros() - nStart;
if (fBenchmark)
printf("- Verify %u txins: %.2fms (%.3fms/txin)\n", nInputs - 1, 0.001 * nTime2, nInputs <= 1 ? 0 : 0.001 * nTime2 / (nInputs-1));
@@ -1728,10 +1695,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
{
if (pindex->GetUndoPos().IsNull()) {
CDiskBlockPos pos;
- if (!FindUndoPos(pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
+ if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock() : FindUndoPos failed");
if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash()))
- return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
+ return state.Abort(_("Failed to write undo data"));
// update nUndoPos in block index
pindex->nUndoPos = pos.nPos;
@@ -1742,15 +1709,15 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
CDiskBlockIndex blockindex(pindex);
if (!pblocktree->WriteBlockIndex(blockindex))
- return error("ConnectBlock() : WriteBlockIndex failed");
+ return state.Abort(_("Failed to write block index"));
}
if (fTxIndex)
- pblocktree->WriteTxIndex(vPos);
+ if (!pblocktree->WriteTxIndex(vPos))
+ return state.Abort(_("Failed to write transaction index"));
// add this block to the view's block chain
- if (!view.SetBestBlock(pindex))
- return false;
+ assert(view.SetBestBlock(pindex));
// Watch for transactions paying to me
for (unsigned int i=0; i<vtx.size(); i++)
@@ -1759,7 +1726,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return true;
}
-bool SetBestChain(CBlockIndex* pindexNew)
+bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
{
// All modifications to the coin state will be done in this cache.
// Only when all have succeeded, we push it to pcoinsTip.
@@ -1770,13 +1737,14 @@ bool SetBestChain(CBlockIndex* pindexNew)
CBlockIndex* plonger = pindexNew;
while (pfork && pfork != plonger)
{
- while (plonger->nHeight > pfork->nHeight)
- if (!(plonger = plonger->pprev))
- return error("SetBestChain() : plonger->pprev is null");
+ while (plonger->nHeight > pfork->nHeight) {
+ plonger = plonger->pprev;
+ assert(plonger != NULL);
+ }
if (pfork == plonger)
break;
- if (!(pfork = pfork->pprev))
- return error("SetBestChain() : pfork->pprev is null");
+ pfork = pfork->pprev;
+ assert(pfork != NULL);
}
// List of what to disconnect (typically nothing)
@@ -1800,9 +1768,9 @@ bool SetBestChain(CBlockIndex* pindexNew)
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
CBlock block;
if (!block.ReadFromDisk(pindex))
- return error("SetBestBlock() : ReadFromDisk for disconnect failed");
+ return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros();
- if (!block.DisconnectBlock(pindex, view))
+ if (!block.DisconnectBlock(state, pindex, view))
return error("SetBestBlock() : DisconnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
if (fBenchmark)
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
@@ -1820,11 +1788,13 @@ bool SetBestChain(CBlockIndex* pindexNew)
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
CBlock block;
if (!block.ReadFromDisk(pindex))
- return error("SetBestBlock() : ReadFromDisk for connect failed");
+ return state.Abort(_("Failed to read block"));
int64 nStart = GetTimeMicros();
- if (!block.ConnectBlock(pindex, view)) {
- InvalidChainFound(pindexNew);
- InvalidBlockFound(pindex);
+ if (!block.ConnectBlock(state, pindex, view)) {
+ if (state.IsInvalid()) {
+ InvalidChainFound(pindexNew);
+ InvalidBlockFound(pindex);
+ }
return error("SetBestBlock() : ConnectBlock %s failed", BlockHashStr(pindex->GetBlockHash()).c_str());
}
if (fBenchmark)
@@ -1838,8 +1808,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Flush changes to global coin state
int64 nStart = GetTimeMicros();
int nModified = view.GetCacheSize();
- if (!view.Flush())
- return error("SetBestBlock() : unable to modify coin state");
+ assert(view.Flush());
int64 nTime = GetTimeMicros() - nStart;
if (fBenchmark)
printf("- Flush %i transactions: %.2fms (%.4fms/tx)\n", nModified, 0.001 * nTime, 0.001 * nTime / nModified);
@@ -1847,10 +1816,17 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload();
if (!fIsInitialDownload || pcoinsTip->GetCacheSize() > nCoinCacheSize) {
+ // Typical CCoins structures on disk are around 100 bytes in size.
+ // Pushing a new one to the database can cause it to be written
+ // twice (once in the log, and once in the tables). This is already
+ // an overestimation, as most will delete an existing entry or
+ // overwrite one. Still, use a conservative safety factor of 2.
+ if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
+ return state.Error();
FlushBlockFile();
pblocktree->Sync();
if (!pcoinsTip->Flush())
- return false;
+ return state.Abort(_("Failed to write to coin database"));
}
// At this point, all changes have been done to the database.
@@ -1867,8 +1843,11 @@ bool SetBestChain(CBlockIndex* pindexNew)
pindex->pprev->pnext = pindex;
// Resurrect memory transactions that were in the disconnected branch
- BOOST_FOREACH(CTransaction& tx, vResurrect)
- tx.AcceptToMemoryPool();
+ BOOST_FOREACH(CTransaction& tx, vResurrect) {
+ // ignore validation errors in resurrected transactions
+ CValidationState stateDummy;
+ tx.AcceptToMemoryPool(stateDummy, true, false);
+ }
// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH(CTransaction& tx, vDelete) {
@@ -1925,17 +1904,16 @@ bool SetBestChain(CBlockIndex* pindexNew)
}
-bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
+bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
- return error("AddToBlockIndex() : %s already exists", BlockHashStr(hash).c_str());
+ return state.Invalid(error("AddToBlockIndex() : %s already exists", BlockHashStr(hash).c_str()));
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(*this);
- if (!pindexNew)
- return error("AddToBlockIndex() : new CBlockIndex failed");
+ 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);
@@ -1953,10 +1931,11 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA;
setBlockIndexValid.insert(pindexNew);
- pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew));
+ if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
+ return state.Abort(_("Failed to write block index"));
// New best?
- if (!ConnectBestBlock())
+ if (!ConnectBestBlock(state))
return false;
if (pindexNew == pindexBest)
@@ -1967,14 +1946,15 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
hashPrevBestCoinBase = GetTxHash(0);
}
- pblocktree->Flush();
+ if (!pblocktree->Flush())
+ return state.Abort(_("Failed to sync block index"));
uiInterface.NotifyBlocksChanged();
return true;
}
-bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime, bool fKnown = false)
+bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64 nTime, bool fKnown = false)
{
bool fUpdatedLast = false;
@@ -1990,7 +1970,7 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh
} else {
while (infoLastBlockFile.nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
printf("Leaving block file %i: %s\n", nLastBlockFile, infoLastBlockFile.ToString().c_str());
- FlushBlockFile();
+ FlushBlockFile(true);
nLastBlockFile++;
infoLastBlockFile.SetNull();
pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile); // check whether data for the new file somehow already exist; can fail just fine
@@ -2016,19 +1996,19 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh
}
}
else
- return error("FindBlockPos() : out of disk space");
+ return state.Error();
}
}
if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- return error("FindBlockPos() : cannot write updated block info");
+ return state.Abort(_("Failed to write file info"));
if (fUpdatedLast)
pblocktree->WriteLastBlockFile(nLastBlockFile);
return true;
}
-bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
+bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
{
pos.nFile = nFile;
@@ -2039,15 +2019,15 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
pos.nPos = infoLastBlockFile.nUndoSize;
nNewSize = (infoLastBlockFile.nUndoSize += nAddSize);
if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- return error("FindUndoPos() : cannot write updated block info");
+ return state.Abort(_("Failed to write block info"));
} else {
CBlockFileInfo info;
if (!pblocktree->ReadBlockFileInfo(nFile, info))
- return error("FindUndoPos() : cannot read block info");
+ return state.Abort(_("Failed to read block info"));
pos.nPos = info.nUndoSize;
nNewSize = (info.nUndoSize += nAddSize);
if (!pblocktree->WriteBlockFileInfo(nFile, info))
- return error("FindUndoPos() : cannot write updated block info");
+ return state.Abort(_("Failed to write block info"));
}
unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;
@@ -2062,41 +2042,41 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
}
}
else
- return error("FindUndoPos() : out of disk space");
+ return state.Error();
}
return true;
}
-bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
+bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const
{
// 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)
- return DoS(100, error("CheckBlock() : size limits failed"));
+ return state.DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits))
- return DoS(50, error("CheckBlock() : proof of work failed"));
+ return state.DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp
if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
- return error("CheckBlock() : block timestamp too far in the future");
+ 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())
- return DoS(100, error("CheckBlock() : first tx is not coinbase"));
+ return state.DoS(100, error("CheckBlock() : first tx is not coinbase"));
for (unsigned int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
- return DoS(100, error("CheckBlock() : more than one coinbase"));
+ return state.DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)
- if (!tx.CheckTransaction())
- return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
+ if (!tx.CheckTransaction(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
@@ -2110,7 +2090,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
uniqueTx.insert(GetTxHash(i));
}
if (uniqueTx.size() != vtx.size())
- return DoS(100, error("CheckBlock() : duplicate transaction"));
+ return state.DoS(100, error("CheckBlock() : duplicate transaction"));
unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
@@ -2118,21 +2098,21 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
nSigOps += tx.GetLegacySigOpCount();
}
if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
+ return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkle root
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
- return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
+ return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
}
-bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
+bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
- return error("AcceptBlock() : block already in mapBlockIndex");
+ return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
// Get prev block index
CBlockIndex* pindexPrev = NULL;
@@ -2140,26 +2120,26 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
if (hash != hashGenesisBlock) {
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end())
- return DoS(10, error("AcceptBlock() : prev block not found"));
+ 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))
- return DoS(100, error("AcceptBlock() : incorrect proof of work"));
+ return state.DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
- return error("AcceptBlock() : block's timestamp is too early");
+ return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.IsFinal(nHeight, GetBlockTime()))
- return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
+ 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
if (!Checkpoints::CheckBlock(nHeight, hash))
- return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
+ 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)
@@ -2167,7 +2147,7 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
(fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
{
- return error("AcceptBlock() : rejected nVersion=1 block");
+ return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"));
}
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
@@ -2179,23 +2159,27 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
{
CScript expect = CScript() << nHeight;
if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
- return DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
+ return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
}
}
}
// Write block to history file
- unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- if (dbp != NULL)
- blockPos = *dbp;
- if (!FindBlockPos(blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
- return error("AcceptBlock() : FindBlockPos failed");
- if (dbp == NULL)
- if (!WriteToDisk(blockPos))
- return error("AcceptBlock() : WriteToDisk failed");
- if (!AddToBlockIndex(blockPos))
- return error("AcceptBlock() : AddToBlockIndex failed");
+ try {
+ unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
+ CDiskBlockPos blockPos;
+ if (dbp != NULL)
+ blockPos = *dbp;
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
+ return error("AcceptBlock() : FindBlockPos failed");
+ if (dbp == NULL)
+ if (!WriteToDisk(blockPos))
+ return state.Abort(_("Failed to write block"));
+ if (!AddToBlockIndex(state, blockPos))
+ return error("AcceptBlock() : AddToBlockIndex failed");
+ } catch(std::runtime_error &e) {
+ return state.Abort(_("System error: ") + e.what());
+ }
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
@@ -2222,17 +2206,17 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
-bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
+bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash))
- return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, BlockHashStr(hash).c_str());
+ return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, BlockHashStr(hash).c_str()));
if (mapOrphanBlocks.count(hash))
- return error("ProcessBlock() : already have block (orphan) %s", BlockHashStr(hash).c_str());
+ return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", BlockHashStr(hash).c_str()));
// Preliminary checks
- if (!pblock->CheckBlock())
+ if (!pblock->CheckBlock(state))
return error("ProcessBlock() : CheckBlock FAILED");
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
@@ -2242,9 +2226,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
if (deltaTime < 0)
{
- if (pfrom)
- pfrom->Misbehaving(100);
- return error("ProcessBlock() : block with timestamp before last checkpoint");
+ return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"));
}
CBigNum bnNewBlock;
bnNewBlock.SetCompact(pblock->nBits);
@@ -2252,9 +2234,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
if (bnNewBlock > bnRequired)
{
- if (pfrom)
- pfrom->Misbehaving(100);
- return error("ProcessBlock() : block with too little proof-of-work");
+ return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"));
}
}
@@ -2277,7 +2257,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
}
// Store to disk
- if (!pblock->AcceptBlock(dbp))
+ if (!pblock->AcceptBlock(state, dbp))
return error("ProcessBlock() : AcceptBlock FAILED");
// Recursively process any orphan blocks that depended on this one
@@ -2291,7 +2271,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
++mi)
{
CBlock* pblockOrphan = (*mi).second;
- if (pblockOrphan->AcceptBlock())
+ // 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))
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
@@ -2463,6 +2445,14 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
+bool AbortNode(const std::string &strMessage) {
+ fRequestShutdown = true;
+ strMiscWarning = strMessage;
+ printf("*** %s\n", strMessage.c_str());
+ uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MODAL);
+ StartShutdown();
+ return false;
+}
bool CheckDiskSpace(uint64 nAdditionalBytes)
{
@@ -2470,15 +2460,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
// Check for nMinDiskSpace bytes (currently 50MB)
if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes)
- {
- fShutdown = true;
- string strMessage = _("Error: Disk space is low!");
- strMiscWarning = strMessage;
- printf("*** %s\n", strMessage.c_str());
- uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR);
- StartShutdown();
- return false;
- }
+ return AbortNode(_("Error: Disk space is low!"));
+
return true;
}
@@ -2609,7 +2592,7 @@ bool VerifyDB() {
// Verify blocks in the best chain
int nCheckLevel = GetArg("-checklevel", 3);
- int nCheckDepth = GetArg( "-checkblocks", 2500);
+ int nCheckDepth = GetArg( "-checkblocks", 288);
if (nCheckDepth == 0)
nCheckDepth = 1000000000; // suffices until the year 19000
if (nCheckDepth > nBestHeight)
@@ -2620,6 +2603,7 @@ bool VerifyDB() {
CBlockIndex* pindexState = pindexBest;
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
+ CValidationState state;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
@@ -2629,7 +2613,7 @@ bool VerifyDB() {
if (!block.ReadFromDisk(pindex))
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
// check level 1: verify block validity
- if (nCheckLevel >= 1 && !block.CheckBlock())
+ if (nCheckLevel >= 1 && !block.CheckBlock(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) {
@@ -2643,7 +2627,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(pindex, coins, &fClean))
+ if (!block.DisconnectBlock(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) {
@@ -2664,7 +2648,7 @@ bool VerifyDB() {
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(pindex, coins))
+ if (!block.ConnectBlock(state, pindex, coins))
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
}
}
@@ -2674,6 +2658,18 @@ bool VerifyDB() {
return true;
}
+void UnloadBlockIndex()
+{
+ mapBlockIndex.clear();
+ setBlockIndexValid.clear();
+ pindexGenesisBlock = NULL;
+ nBestHeight = 0;
+ bnBestChainWork = 0;
+ bnBestInvalidWork = 0;
+ hashBestChain = 0;
+ pindexBest = NULL;
+}
+
bool LoadBlockIndex()
{
if (fTestNet)
@@ -2691,18 +2687,22 @@ bool LoadBlockIndex()
if (!fReindex && !LoadBlockIndexDB())
return false;
- //
- // Init with genesis block
- //
- if (mapBlockIndex.empty())
- {
- fTxIndex = GetBoolArg("-txindex", false);
- pblocktree->WriteFlag("txindex", fTxIndex);
- printf("Initializing databases...\n");
+ return true;
+}
- if (fReindex)
- return true;
+bool InitBlockIndex() {
+ // Check whether we're already initialized
+ if (pindexGenesisBlock != NULL)
+ return true;
+
+ // Use the provided setting for -txindex in the new database
+ fTxIndex = GetBoolArg("-txindex", false);
+ pblocktree->WriteFlag("txindex", fTxIndex);
+ printf("Initializing databases...\n");
+
+ // Only add the genesis block if not reindexing (in which case we reuse the one already on disk)
+ if (!fReindex) {
// Genesis Block:
// CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
// CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
@@ -2743,14 +2743,19 @@ bool LoadBlockIndex()
assert(hash == hashGenesisBlock);
// Start new block file
- unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
- CDiskBlockPos blockPos;
- if (!FindBlockPos(blockPos, nBlockSize+8, 0, block.nTime))
- return error("AcceptBlock() : FindBlockPos failed");
- if (!block.WriteToDisk(blockPos))
- return error("LoadBlockIndex() : writing genesis block to disk failed");
- if (!block.AddToBlockIndex(blockPos))
- return error("LoadBlockIndex() : genesis block not accepted");
+ try {
+ unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
+ CDiskBlockPos blockPos;
+ CValidationState state;
+ if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
+ return error("AcceptBlock() : FindBlockPos failed");
+ if (!block.WriteToDisk(blockPos))
+ return error("LoadBlockIndex() : writing genesis block to disk failed");
+ if (!block.AddToBlockIndex(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());
+ }
}
return true;
@@ -2833,7 +2838,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
int64 nStart = GetTimeMillis();
int nLoaded = 0;
- {
+ try {
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION);
uint64 nStartByte = 0;
if (dbp) {
@@ -2879,14 +2884,19 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
LOCK(cs_main);
if (dbp)
dbp->nPos = nBlockPos;
- if (ProcessBlock(NULL, &block, dbp))
+ CValidationState state;
+ if (ProcessBlock(state, NULL, &block, dbp))
nLoaded++;
+ if (state.IsError())
+ break;
}
} catch (std::exception &e) {
printf("%s() : Deserialize or I/O error caught during load\n", __PRETTY_FUNCTION__);
}
}
fclose(fileIn);
+ } catch(std::runtime_error &e) {
+ AbortNode(_("Error: system error: ") + e.what());
}
if (nLoaded > 0)
printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart);
@@ -3456,7 +3466,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
- if (tx.AcceptToMemoryPool(true, &fMissingInputs))
+ CValidationState state;
+ if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
{
RelayTransaction(tx, inv.hash, vMsg);
mapAlreadyAskedFor.erase(inv);
@@ -3476,8 +3487,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CDataStream(vMsg) >> tx;
CInv inv(MSG_TX, tx.GetHash());
bool fMissingInputs2 = false;
+ // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get anyone relaying LegitTxX banned)
+ CValidationState stateDummy;
- if (tx.AcceptToMemoryPool(true, &fMissingInputs2))
+ if (tx.AcceptToMemoryPool(stateDummy, true, true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
RelayTransaction(tx, inv.hash, vMsg);
@@ -3487,9 +3500,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
else if (!fMissingInputs2)
{
- // invalid orphan
+ // invalid or too-little-fee orphan
vEraseQueue.push_back(inv.hash);
- printf(" removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
+ printf(" removed orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
}
}
}
@@ -3506,7 +3519,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (nEvicted > 0)
printf("mapOrphan overflow, removed %u tx\n", nEvicted);
}
- if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
+ int nDoS;
+ if (state.IsInvalid(nDoS))
+ pfrom->Misbehaving(nDoS);
}
@@ -3521,9 +3536,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_BLOCK, block.GetHash());
pfrom->AddInventoryKnown(inv);
- if (ProcessBlock(pfrom, &block))
+ CValidationState state;
+ if (ProcessBlock(state, pfrom, &block))
mapAlreadyAskedFor.erase(inv);
- if (block.nDoS) pfrom->Misbehaving(block.nDoS);
+ int nDoS;
+ if (state.IsInvalid(nDoS))
+ pfrom->Misbehaving(nDoS);
}
@@ -3811,7 +3829,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
// Resend wallet transactions that haven't gotten in a block yet
- ResendWalletTransactions();
+ // Except during reindex, importing and IBD, when old wallet
+ // transactions become unconfirmed and spams other nodes.
+ if (!fReindex && !fImporting && !IsInitialBlockDownload())
+ {
+ ResendWalletTransactions();
+ }
// Address refresh broadcast
static int64 nLastRebroadcast;
@@ -4273,12 +4296,13 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
- if (!tx.CheckInputs(viewTemp, true, SCRIPT_VERIFY_P2SH))
+ CValidationState state;
+ if (!tx.CheckInputs(state, viewTemp, true, SCRIPT_VERIFY_P2SH))
continue;
CTxUndo txundo;
uint256 hash = tx.GetHash();
- if (!tx.UpdateCoins(viewTemp, txundo, pindexPrev->nHeight+1, hash))
+ if (!tx.UpdateCoins(state, viewTemp, txundo, pindexPrev->nHeight+1, hash))
continue;
// push changes from the second layer cache to the first one
@@ -4336,7 +4360,8 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
CCoinsViewCache viewNew(*pcoinsTip, true);
- if (!pblock->ConnectBlock(&indexDummy, viewNew, true))
+ CValidationState state;
+ if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true))
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
}
@@ -4438,7 +4463,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
}
// Process this block the same as if we had received it from another node
- if (!ProcessBlock(NULL, pblock))
+ CValidationState state;
+ if (!ProcessBlock(state, NULL, pblock))
return error("BitcoinMiner : ProcessBlock, block not accepted");
}
diff --git a/src/main.h b/src/main.h
index d5f7093e42..c1af0c3706 100644
--- a/src/main.h
+++ b/src/main.h
@@ -28,6 +28,8 @@ struct CBlockIndexWorkComparator;
static const unsigned int MAX_BLOCK_SIZE = 1000000;
/** The maximum size for mined blocks */
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
+/** The maximum size for transactions we're willing to relay/mine **/
+static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** The maximum number of orphan transactions kept in memory */
@@ -106,15 +108,17 @@ static const uint64 nMinDiskSpace = 52428800;
class CReserveKey;
class CCoinsDB;
class CBlockTreeDB;
-class CDiskBlockPos;
+struct CDiskBlockPos;
class CCoins;
class CTxUndo;
class CCoinsView;
class CCoinsViewCache;
class CScriptCheck;
+class CValidationState;
struct CBlockTemplate;
+
/** Register a wallet to receive updates from core */
void RegisterWallet(CWallet* pwalletIn);
/** Unregister a wallet from core */
@@ -122,7 +126,7 @@ void UnregisterWallet(CWallet* pwalletIn);
/** Push an updated transaction to all registered wallets */
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
/** Process an incoming block */
-bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
+bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64 nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -131,8 +135,12 @@ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Import blocks from an external file */
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp = NULL);
+/** Initialize a new block tree database + block data on disk */
+bool InitBlockIndex();
/** Load the block tree and coins database from disk */
bool LoadBlockIndex();
+/** Unload database information */
+void UnloadBlockIndex();
/** Verify consistency of the block and coin databases */
bool VerifyDB();
/** Print the loaded block tree */
@@ -172,13 +180,15 @@ std::string GetWarnings(std::string strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
/** Connect/disconnect blocks until pindexNew is the new tip of the active block chain */
-bool SetBestChain(CBlockIndex* pindexNew);
+bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew);
/** Find the best known block, and make it the tip of the block chain */
-bool ConnectBestBlock();
+bool ConnectBestBlock(CValidationState &state);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
/** Verify a signature */
bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
+/** Abort with a message */
+bool AbortNode(const std::string &msg);
@@ -454,7 +464,6 @@ public:
-
enum GetMinFee_mode
{
GMF_BLOCK,
@@ -474,10 +483,6 @@ public:
std::vector<CTxOut> vout;
unsigned int nLockTime;
- // Denial-of-service detection:
- mutable int nDoS;
- bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
-
CTransaction()
{
SetNull();
@@ -498,7 +503,6 @@ public:
vin.clear();
vout.clear();
nLockTime = 0;
- nDoS = 0; // Denial-of-service prevention
}
bool IsNull() const
@@ -654,27 +658,24 @@ public:
}
- // Do all possible client-mode checks
- bool ClientCheckInputs() const;
-
// Check whether all prevouts of this transaction are present in the UTXO set represented by view
bool HaveInputs(CCoinsViewCache &view) const;
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
// instead of being performed inline.
- bool CheckInputs(CCoinsViewCache &view, bool fScriptChecks = true,
+ bool CheckInputs(CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC,
std::vector<CScriptCheck> *pvChecks = NULL) const;
// Apply the effects of this transaction on the UTXO set represented by view
- bool UpdateCoins(CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
+ bool UpdateCoins(CValidationState &state, CCoinsViewCache &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
// Context-independent validity checks
- bool CheckTransaction() const;
+ bool CheckTransaction(CValidationState &state) const;
// Try to accept this transaction into the memory pool
- bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
+ bool AcceptToMemoryPool(CValidationState &state, bool fCheckInputs=true, bool fLimitFree = true, bool* pfMissingInputs=NULL);
protected:
static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
@@ -814,22 +815,12 @@ public:
uint256 hashChecksum;
try {
filein >> *this;
+ filein >> hashChecksum;
}
catch (std::exception &e) {
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
}
- // for compatibility with pre-release code that didn't write checksums to undo data
- // TODO: replace by a simply 'filein >> hashChecksum' in the above try block
- try {
- filein >> hashChecksum;
- } catch (std::exception &e) {
- hashChecksum = 0;
- }
- uint32_t hashInit = hashChecksum.Get64(0) & 0xFFFFFFFFUL;
- if (hashChecksum == 0 || memcmp(&hashInit, pchMessageStart, 4) == 0)
- return true;
-
// Verify checksum
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
hasher << hashBlock;
@@ -1163,7 +1154,7 @@ public:
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(bool fCheckInputs=true);
+ bool AcceptToMemoryPool(bool fCheckInputs=true, bool fLimitFree=true);
};
@@ -1339,10 +1330,6 @@ public:
// memory only
mutable std::vector<uint256> vMerkleTree;
- // Denial-of-service detection:
- mutable int nDoS;
- bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
-
CBlock()
{
SetNull();
@@ -1365,7 +1352,6 @@ public:
CBlockHeader::SetNull();
vtx.clear();
vMerkleTree.clear();
- nDoS = 0;
}
CBlockHeader GetBlockHeader() const
@@ -1513,23 +1499,23 @@ public:
* 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(CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL);
+ 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(CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false);
+ 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(const CDiskBlockPos &pos);
+ bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos);
// Context-independent validity checks
- bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const;
+ 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(CDiskBlockPos *dbp = NULL);
+ bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL);
};
@@ -1896,6 +1882,52 @@ public:
}
};
+/** Capture information about block/transaction validation */
+class CValidationState {
+private:
+ enum mode_state {
+ MODE_VALID, // everything ok
+ MODE_INVALID, // network rule violation (DoS value may be set)
+ MODE_ERROR, // run-time error
+ } mode;
+ int nDoS;
+public:
+ CValidationState() : mode(MODE_VALID), nDoS(0) {}
+ bool DoS(int level, bool ret = false) {
+ if (mode == MODE_ERROR)
+ return ret;
+ nDoS += level;
+ mode = MODE_INVALID;
+ return ret;
+ }
+ bool Invalid(bool ret = false) {
+ return DoS(0, ret);
+ }
+ bool Error() {
+ mode = MODE_ERROR;
+ return false;
+ }
+ bool Abort(const std::string &msg) {
+ AbortNode(msg);
+ return Error();
+ }
+ bool IsValid() {
+ return mode == MODE_VALID;
+ }
+ bool IsInvalid() {
+ return mode == MODE_INVALID;
+ }
+ bool IsError() {
+ return mode == MODE_ERROR;
+ }
+ bool IsInvalid(int &nDoSOut) {
+ if (IsInvalid()) {
+ nDoSOut = nDoS;
+ return true;
+ }
+ return false;
+ }
+};
@@ -2044,7 +2076,7 @@ public:
std::map<uint256, CTransaction> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
- bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs);
+ bool accept(CValidationState &state, CTransaction &tx, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs);
bool addUnchecked(const uint256& hash, CTransaction &tx);
bool remove(const CTransaction &tx, bool fRecursive = false);
bool removeConflicts(const CTransaction &tx);
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index c3cbe90bcd..7509e2798e 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -4,6 +4,9 @@
DEPSDIR:=/usr/i586-mingw32msvc
+CC := i586-mingw32msvc-gcc
+CXX := i586-mingw32msvc-g++
+
USE_UPNP:=0
USE_IPV6:=1
@@ -58,6 +61,7 @@ LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l w
HEADERS = $(wildcard *.h)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -95,8 +99,7 @@ all: bitcoind.exe
DEFS += -I"$(CURDIR)/leveldb/include"
DEFS += -I"$(CURDIR)/leveldb/helpers"
leveldb/libleveldb.a:
- @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="$(INCLUDEPATHS)" LDFLAGS="$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd ..
-obj/leveldb.o: leveldb/libleveldb.a
+ @echo "Building LevelDB ..." && cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd ..
obj/build.h: FORCE
/bin/sh ../share/genbuild.sh obj/build.h
@@ -104,18 +107,18 @@ version.cpp: obj/build.h
DEFS += -DHAVE_BUILD_INFO
obj/%.o: %.cpp $(HEADERS)
- i586-mingw32msvc-g++ -c $(CFLAGS) -o $@ $<
+ $(CXX) -c $(CFLAGS) -o $@ $<
bitcoind.exe: $(OBJS:obj/%=obj/%)
- i586-mingw32msvc-g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp $(HEADERS)
- i586-mingw32msvc-g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
+ $(CXX) -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- i586-mingw32msvc-g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework-mt-s $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework-mt-s $(LIBS)
clean:
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 366d32bd86..2e092ff686 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -15,6 +15,8 @@
# 'make clean' assumes it is running inside a MSYS shell, and uses 'rm'
# to remove files.
+CXX ?= g++
+
USE_UPNP:=-
USE_IPV6:=1
@@ -67,6 +69,7 @@ LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell
HEADERS = $(wildcard *.h)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -112,23 +115,21 @@ DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- cd leveldb && $(MAKE) OPT="$(DEBUGFLAGS)" TARGET_OS=NATIVE_WINDOWS libleveldb.a libmemenv.a && cd ..
-
-obj/leveldb.o: leveldb/libleveldb.a
+ cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" TARGET_OS=NATIVE_WINDOWS libleveldb.a libmemenv.a && cd ..
obj/%.o: %.cpp $(HEADERS)
- g++ -c $(CFLAGS) -o $@ $<
+ $(CXX) -c $(CFLAGS) -o $@ $<
bitcoind.exe: $(OBJS:obj/%=obj/%)
- g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS)
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
obj-test/%.o: test/%.cpp $(HEADERS)
- g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
+ $(CXX) -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
- g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework$(BOOST_SUFFIX) $(LIBS)
+ $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework$(BOOST_SUFFIX) $(LIBS)
clean:
rm -f bitcoind.exe test_bitcoin.exe
diff --git a/src/makefile.osx b/src/makefile.osx
index 8b7c559fa1..cdee781257 100644
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -62,7 +62,7 @@ ifdef RELEASE
# the same way.
CFLAGS = -mmacosx-version-min=10.5 -arch i386 -O3
else
-CFLAGS = -g
+DEBUGFLAGS = -g
endif
# ppc doesn't work because we don't support big-endian
@@ -70,6 +70,7 @@ CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
$(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -130,8 +131,7 @@ LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
-obj/leveldb.o: leveldb/libleveldb.a
+ @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(CFLAGS)" libleveldb.a libmemenv.a && cd ..
# auto-generated dependencies:
-include obj/*.P
@@ -171,5 +171,6 @@ clean:
-rm -f obj/*.P
-rm -f obj-test/*.P
-rm -f obj/build.h
+ -cd leveldb && $(MAKE) clean || true
FORCE:
diff --git a/src/makefile.unix b/src/makefile.unix
index 14cf1b8fa5..ece2f59cf5 100644
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -7,7 +7,7 @@ USE_IPV6:=1
LINK:=$(CXX)
-DEFS=-DBOOST_SPIRIT_THREADSAFE
+DEFS=-DBOOST_SPIRIT_THREADSAFE -D_FILE_OFFSET_BITS=64
DEFS += $(addprefix -I,$(CURDIR) $(CURDIR)/obj $(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
LIBS = $(addprefix -L,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
@@ -101,6 +101,7 @@ xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-para
xLDFLAGS=$(LDHARDENING) $(LDFLAGS)
OBJS= \
+ leveldb/libleveldb.a \
obj/alert.o \
obj/version.o \
obj/checkpoints.o \
@@ -142,12 +143,12 @@ test check: test_bitcoin FORCE
#
# LevelDB support
#
+MAKEOVERRIDES =
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
leveldb/libleveldb.a:
- @echo "Building LevelDB ..." && cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd ..
-obj/leveldb.o: leveldb/libleveldb.a
+ @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(xCXXFLAGS)" libleveldb.a libmemenv.a && cd ..
# auto-generated dependencies:
-include obj/*.P
@@ -187,5 +188,6 @@ clean:
-rm -f obj/*.P
-rm -f obj-test/*.P
-rm -f obj/build.h
+ -cd leveldb && $(MAKE) clean || true
FORCE:
diff --git a/src/net.cpp b/src/net.cpp
index 319739429c..3406a28b0e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -72,6 +72,9 @@ CCriticalSection cs_vOneShots;
set<CNetAddr> setservAddNodeAddresses;
CCriticalSection cs_setservAddNodeAddresses;
+vector<std::string> vAddedNodes;
+CCriticalSection cs_vAddedNodes;
+
static CSemaphore *semOutbound = NULL;
void AddOneShot(string strDest)
@@ -1142,11 +1145,17 @@ void MapPort()
// Each pair gives a source name and a seed name.
// The first name is used as information source for addrman.
// The second name should resolve to a list of seed addresses.
-static const char *strDNSSeed[][2] = {
+static const char *strMainNetDNSSeed[][2] = {
{"bitcoin.sipa.be", "seed.bitcoin.sipa.be"},
{"bluematt.me", "dnsseed.bluematt.me"},
{"dashjr.org", "dnsseed.bitcoin.dashjr.org"},
{"xf2.org", "bitseed.xf2.org"},
+ {NULL, NULL}
+};
+
+static const char *strTestNetDNSSeed[][2] = {
+ {"bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org"},
+ {NULL, NULL}
};
void ThreadDNSAddressSeed(void* parg)
@@ -1172,32 +1181,31 @@ void ThreadDNSAddressSeed(void* parg)
void ThreadDNSAddressSeed2(void* parg)
{
+ static const char *(*strDNSSeed)[2] = fTestNet ? strTestNetDNSSeed : strMainNetDNSSeed;
+
printf("ThreadDNSAddressSeed started\n");
int found = 0;
- if (!fTestNet)
- {
- printf("Loading addresses from DNS seeds (could take a while)\n");
-
- for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
- if (HaveNameProxy()) {
- AddOneShot(strDNSSeed[seed_idx][1]);
- } else {
- vector<CNetAddr> vaddr;
- vector<CAddress> vAdd;
- if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
+ printf("Loading addresses from DNS seeds (could take a while)\n");
+
+ for (unsigned int seed_idx = 0; strDNSSeed[seed_idx][0] != NULL; seed_idx++) {
+ if (HaveNameProxy()) {
+ AddOneShot(strDNSSeed[seed_idx][1]);
+ } else {
+ vector<CNetAddr> vaddr;
+ vector<CAddress> vAdd;
+ if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
+ {
+ BOOST_FOREACH(CNetAddr& ip, vaddr)
{
- BOOST_FOREACH(CNetAddr& ip, vaddr)
- {
- int nOneDay = 24*3600;
- CAddress addr = CAddress(CService(ip, GetDefaultPort()));
- addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
- vAdd.push_back(addr);
- found++;
- }
+ int nOneDay = 24*3600;
+ CAddress addr = CAddress(CService(ip, GetDefaultPort()));
+ addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
+ vAdd.push_back(addr);
+ found++;
}
- addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
}
+ addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
}
}
@@ -1217,83 +1225,81 @@ void ThreadDNSAddressSeed2(void* parg)
unsigned int pnSeed[] =
{
- 0x959bd347, 0xf8de42b2, 0x73bc0518, 0xea6edc50, 0x21b00a4d, 0xc725b43d, 0xd665464d, 0x1a2a770e,
- 0x27c93946, 0x65b2fa46, 0xb80ae255, 0x66b3b446, 0xb1877a3e, 0x6ee89e3e, 0xc3175b40, 0x2a01a83c,
- 0x95b1363a, 0xa079ad3d, 0xe6ca801f, 0x027f4f4a, 0x34f7f03a, 0xf790f04a, 0x16ca801f, 0x2f4d5e40,
- 0x3a4d5e40, 0xc43a322e, 0xc8159753, 0x14d4724c, 0x7919a118, 0xe0bdb34e, 0x68a16b2e, 0xff64b44d,
- 0x6099115b, 0x9b57b05b, 0x7bd1b4ad, 0xdf95944f, 0x29d2b73d, 0xafa8db79, 0xe247ba41, 0x24078348,
- 0xf722f03c, 0x33567ebc, 0xace64ed4, 0x984d3932, 0xb5f34e55, 0x27b7024d, 0x94579247, 0x8894042e,
- 0x9357d34c, 0x1063c24b, 0xcaa228b1, 0xa3c5a8b2, 0x5dc64857, 0xa2c23643, 0xa8369a54, 0x31203077,
- 0x00707c5c, 0x09fc0b3a, 0x272e9e2e, 0xf80f043e, 0x9449ca3e, 0x5512c33e, 0xd106b555, 0xe8024157,
- 0xe288ec29, 0xc79c5461, 0xafb63932, 0xdb02ab4b, 0x0e512777, 0x8a145a4c, 0xb201ff4f, 0x5e09314b,
- 0xcd9bfbcd, 0x1c023765, 0x4394e75c, 0xa728bd4d, 0x65331552, 0xa98420b1, 0x89ecf559, 0x6e80801f,
- 0xf404f118, 0xefd62b51, 0x05918346, 0x9b186d5f, 0xacabab46, 0xf912e255, 0xc188ea62, 0xcc55734e,
- 0xc668064d, 0xd77a4558, 0x46201c55, 0xf17dfc80, 0xf7142f2e, 0x87bfb718, 0x8aa54fb2, 0xc451d518,
- 0xc4ae8831, 0x8dd44d55, 0x5bbd206c, 0x64536b5d, 0x5c667e60, 0x3b064242, 0xfe963a42, 0xa28e6dc8,
- 0xe8a9604a, 0xc989464e, 0xd124a659, 0x50065140, 0xa44dfe5e, 0x1079e655, 0x3fb986d5, 0x47895b18,
- 0x7d3ce4ad, 0x4561ba50, 0x296eec62, 0x255b41ad, 0xaed35ec9, 0x55556f12, 0xc7d3154d, 0x3297b65d,
- 0x8930121f, 0xabf42e4e, 0x4a29e044, 0x1212685d, 0x676c1e40, 0xce009744, 0x383a8948, 0xa2dbd0ad,
- 0xecc2564d, 0x07dbc252, 0x887ee24b, 0x5171644c, 0x6bb798c1, 0x847f495d, 0x4cbb7145, 0x3bb81c32,
- 0x45eb262e, 0xc8015a4e, 0x250a361b, 0xf694f946, 0xd64a183e, 0xd4f1dd59, 0x8f20ffd4, 0x51d9e55c,
- 0x09521763, 0x5e02002e, 0x32c8074d, 0xe685762e, 0x8290b0bc, 0x762a922e, 0xfc5ee754, 0x83a24829,
- 0x775b224d, 0x6295bb4d, 0x38ec0555, 0xbffbba50, 0xe5560260, 0x86b16a7c, 0xd372234e, 0x49a3c24b,
- 0x2f6a171f, 0x4d75ed60, 0xae94115b, 0xcb543744, 0x63080c59, 0x3f9c724c, 0xc977ce18, 0x532efb18,
- 0x69dc3b2e, 0x5f94d929, 0x1732bb4d, 0x9c814b4d, 0xe6b3762e, 0xc024f662, 0x8face35b, 0x6b5b044d,
- 0x798c7b57, 0x79a6b44c, 0x067d3057, 0xf9e94e5f, 0x91cbe15b, 0x71405eb2, 0x2662234e, 0xcbcc4a6d,
- 0xbf69d54b, 0xa79b4e55, 0xec6d3e51, 0x7c0b3c02, 0x60f83653, 0x24c1e15c, 0x1110b62e, 0x10350f59,
- 0xa56f1d55, 0x3509e7a9, 0xeb128354, 0x14268e2e, 0x934e28bc, 0x8e32692e, 0x8331a21f, 0x3e633932,
- 0xc812b12e, 0xc684bf2e, 0x80112d2e, 0xe0ddc96c, 0xc630ca4a, 0x5c09b3b2, 0x0b580518, 0xc8e9d54b,
- 0xd169aa43, 0x17d0d655, 0x1d029963, 0x7ff87559, 0xcb701f1f, 0x6fa3e85d, 0xe45e9a54, 0xf05d1802,
- 0x44d03b2e, 0x837b692e, 0xccd4354e, 0x3d6da13c, 0x3423084d, 0xf707c34a, 0x55f6db3a, 0xad26e442,
- 0x6233a21f, 0x09e80e59, 0x8caeb54d, 0xbe870941, 0xb407d20e, 0x20b51018, 0x56fb152e, 0x460d2a4e,
- 0xbb9a2946, 0x560eb12e, 0xed83dd29, 0xd6724f53, 0xa50aafb8, 0x451346d9, 0x88348e2e, 0x7312fead,
- 0x8ecaf96f, 0x1bda4e5f, 0xf1671e40, 0x3c8c3e3b, 0x4716324d, 0xdde24ede, 0xf98cd17d, 0xa91d4644,
- 0x28124eb2, 0x147d5129, 0xd022042e, 0x61733d3b, 0xad0d5e02, 0x8ce2932e, 0xe5c18502, 0x549c1e32,
- 0x9685801f, 0x86e217ad, 0xd948214b, 0x4110f462, 0x3a2e894e, 0xbd35492e, 0x87e0d558, 0x64b8ef7d,
- 0x7c3eb962, 0x72a84b3e, 0x7cd667c9, 0x28370a2e, 0x4bc60e7b, 0x6fc1ec60, 0x14a6983f, 0x86739a4b,
- 0x46954e5f, 0x32e2e15c, 0x2e9326cf, 0xe5801c5e, 0x379607b2, 0x32151145, 0xf0e39744, 0xacb54c55,
- 0xa37dfb60, 0x83b55cc9, 0x388f7ca5, 0x15034f5f, 0x3e94965b, 0x68e0ffad, 0x35280f59, 0x8fe190cf,
- 0x7c6ba5b2, 0xa5e9db43, 0x4ee1fc60, 0xd9d94e5f, 0x04040677, 0x0ea9b35e, 0x5961f14f, 0x67fda063,
- 0xa48a5a31, 0xc6524e55, 0x283d325e, 0x3f37515f, 0x96b94b3e, 0xacce620e, 0x6481cc5b, 0xa4a06d4b,
- 0x9e95d2d9, 0xe40c03d5, 0xc2f4514b, 0xb79aad44, 0xf64be843, 0xb2064070, 0xfca00455, 0x429dfa4e,
- 0x2323f173, 0xeda4185e, 0xabd5227d, 0x9efd4d58, 0xb1104758, 0x4811e955, 0xbd9ab355, 0xe921f44b,
- 0x9f166dce, 0x09e279b2, 0xe0c9ac7b, 0x7901a5ad, 0xa145d4b0, 0x79104671, 0xec31e35a, 0x4fe0b555,
- 0xc7d9cbad, 0xad057f55, 0xe94cc759, 0x7fe0b043, 0xe4529f2e, 0x0d4dd4b2, 0x9f11a54d, 0x031e2e4e,
- 0xe6014f5f, 0x11d1ca6c, 0x26bd7f61, 0xeb86854f, 0x4d347b57, 0x116bbe2e, 0xdba7234e, 0x7bcbfd2e,
- 0x174dd4b2, 0x6686762e, 0xb089ba50, 0xc6258246, 0x087e767b, 0xc4a8cb4a, 0x595dba50, 0x7f0ae502,
- 0x7b1dbd5a, 0xa0603492, 0x57d1af4b, 0x9e21ffd4, 0x6393064d, 0x7407376e, 0xe484762e, 0x122a4e53,
- 0x4a37aa43, 0x3888a6be, 0xee77864e, 0x039c8dd5, 0x688d89af, 0x0e988f62, 0x08218246, 0xfc2f8246,
- 0xd1d97040, 0xd64cd4b2, 0x5ae4a6b8, 0x7d0de9bc, 0x8d304d61, 0x06c5c672, 0xa4c8bd4d, 0xe0fd373b,
- 0x575ebe4d, 0x72d26277, 0x55570f55, 0x77b154d9, 0xe214293a, 0xfc740f4b, 0xfe3f6a57, 0xa9c55f02,
- 0xae4054db, 0x2394d918, 0xb511b24a, 0xb8741ab2, 0x0758e65e, 0xc7b5795b, 0xb0a30a4c, 0xaf7f170c,
- 0xf3b4762e, 0x8179576d, 0x738a1581, 0x4b95b64c, 0x9829b618, 0x1bea932e, 0x7bdeaa4b, 0xcb5e0281,
- 0x65618f54, 0x0658474b, 0x27066acf, 0x40556d65, 0x7d204d53, 0xf28bc244, 0xdce23455, 0xadc0ff54,
- 0x3863c948, 0xcee34e5f, 0xdeb85e02, 0x2ed17a61, 0x6a7b094d, 0x7f0cfc40, 0x59603f54, 0x3220afbc,
- 0xb5dfd962, 0x125d21c0, 0x13f8d243, 0xacfefb4e, 0x86c2c147, 0x3d8bbd59, 0xbd02a21f, 0x2593042e,
- 0xc6a17a7c, 0x28925861, 0xb487ed44, 0xb5f4fd6d, 0x90c28a45, 0x5a14f74d, 0x43d71b4c, 0x728ebb5d,
- 0x885bf950, 0x08134dd0, 0x38ec046e, 0xc575684b, 0x50082d2e, 0xa2f47757, 0x270f86ae, 0xf3ff6462,
- 0x10ed3f4e, 0x4b58d462, 0xe01ce23e, 0x8c5b092e, 0x63e52f4e, 0x22c1e85d, 0xa908f54e, 0x8591624f,
- 0x2c0fb94e, 0xa280ba3c, 0xb6f41b4c, 0x24f9aa47, 0x27201647, 0x3a3ea6dc, 0xa14fc3be, 0x3c34bdd5,
- 0x5b8d4f5b, 0xaadeaf4b, 0xc71cab50, 0x15697a4c, 0x9a1a734c, 0x2a037d81, 0x2590bd59, 0x48ec2741,
- 0x53489c5b, 0x7f00314b, 0x2170d362, 0xf2e92542, 0x42c10b44, 0x98f0f118, 0x883a3456, 0x099a932e,
- 0xea38f7bc, 0x644e9247, 0xbb61b62e, 0x30e0863d, 0x5f51be54, 0x207215c7, 0x5f306c45, 0xaa7f3932,
- 0x98da7d45, 0x4e339b59, 0x2e411581, 0xa808f618, 0xad2c0c59, 0x54476741, 0x09e99fd1, 0x5db8f752,
- 0xc16df8bd, 0x1dd4b44f, 0x106edf2e, 0x9e15c180, 0x2ad6b56f, 0x633a5332, 0xff33787c, 0x077cb545,
- 0x6610be6d, 0x75aad2c4, 0x72fb4d5b, 0xe81e0f59, 0x576f6332, 0x47333373, 0x351ed783, 0x2d90fb50,
- 0x8d5e0f6c, 0x5b27a552, 0xdb293ebb, 0xe55ef950, 0x4b133ad8, 0x75df975a, 0x7b6a8740, 0xa899464b,
- 0xfab15161, 0x10f8b64d, 0xd055ea4d, 0xee8e146b, 0x4b14afb8, 0x4bc1c44a, 0x9b961dcc, 0xd111ff43,
- 0xfca0b745, 0xc800e412, 0x0afad9d1, 0xf751c350, 0xf9f0cccf, 0xa290a545, 0x8ef13763, 0x7ec70d59,
- 0x2b066acf, 0x65496c45, 0xade02c1b, 0xae6eb077, 0x92c1e65b, 0xc064e6a9, 0xc649e56d, 0x5287a243,
- 0x36de4f5b, 0x5b1df6ad, 0x65c39a59, 0xdba805b2, 0x20067aa8, 0x6457e56d, 0x3cee26cf, 0xfd3ff26d,
- 0x04f86d4a, 0x06b8e048, 0xa93bcd5c, 0x91135852, 0xbe90a643, 0x8fa0094d, 0x06d8215f, 0x2677094d,
- 0xd735685c, 0x164a00c9, 0x5209ac5f, 0xa9564c5c, 0x3b504f5f, 0xcc826bd0, 0x4615042e, 0x5fe13b4a,
- 0x8c81b86d, 0x879ab68c, 0x1de564b8, 0x434487d8, 0x2dcb1b63, 0x82ab524a, 0xb0676abb, 0xa13d9c62,
- 0xdbb5b86d, 0x5b7f4b59, 0xaddfb44d, 0xad773532, 0x3997054c, 0x72cebd89, 0xb194544c, 0xc5b8046e,
- 0x6e1adeb2, 0xaa5abb51, 0xefb54b44, 0x15efc54f, 0xe9f1bc4d, 0x5f401b6c, 0x97f018ad, 0xc82f9252,
- 0x2cdc762e, 0x8e52e56d, 0x1827175e, 0x9b7d7d80, 0xb2ad6845, 0x51065140, 0x71180a18, 0x5b27006c,
- 0x0621e255, 0x721cbe58, 0x670c0cb8, 0xf8bd715d, 0xe0bdc5d9, 0xed843501, 0x4b84554d, 0x7f1a18bc,
- 0x53bcaf47, 0x5729d35f, 0xf0dda246, 0x22382bd0, 0x4d641fb0, 0x316afcde, 0x50a22f1f, 0x73608046,
- 0xc461d84a, 0xb2dbe247,
+ 0xe473042e, 0xb177f2ad, 0xd63f3fb2, 0xf864f736, 0x44a23ac7, 0xcf6d9650, 0xd648042e, 0x0536f447,
+ 0x3c654ed0, 0x3e16a5bc, 0xa38e09b0, 0xdfae795b, 0xabfeca5b, 0x94ad7840, 0xf3b9f1c7, 0xbe70e0ad,
+ 0x3bbd09b0, 0x8d0c7dd5, 0x3b2a7332, 0x1a06175e, 0x581f175e, 0xca0d2dcc, 0x0fdbc658, 0xcf591ec7,
+ 0x295a12b2, 0xb4707bce, 0x68bb09b0, 0x4e735747, 0x89709553, 0x05a7814e, 0x5b8ec658, 0x402c5512,
+ 0xe80d0905, 0x17681a5e, 0xc02aa748, 0x9f811741, 0x5f321cb0, 0x23e1ee47, 0xaf7f170c, 0xaa240ab0,
+ 0xedea6257, 0x76106bc1, 0x2cf310cc, 0x08612acb, 0x9c682e4e, 0x8e963c6c, 0x443c795b, 0x22e246b8,
+ 0xfa1f2dcc, 0x90118140, 0x3821042e, 0x33c3fd2e, 0x10046d5b, 0x40d14b3e, 0x7fb8f8ce, 0x67696550,
+ 0xeeecbe58, 0x4f341745, 0x46b8fbd5, 0xc8463932, 0x6b73e862, 0x4c715932, 0x4a6785d5, 0xce3a64c2,
+ 0xde9604c7, 0x9b06884f, 0x18002a45, 0xea9bc345, 0xc4f1c658, 0xe475c1c7, 0xdd3e795b, 0x9722175e,
+ 0x34562f4e, 0x66c46e4e, 0x40bb1243, 0x7d9171d0, 0x17b8dbd5, 0x63cbfd2e, 0x1a08b8d8, 0x6175a73b,
+ 0x228d2660, 0x8627c658, 0x9c566644, 0x38cca5bc, 0x3089de5b, 0x92e25f5d, 0xa393f73f, 0xcc92dc3e,
+ 0x27487446, 0x62cbfd2e, 0x9d983b45, 0xf72a09b0, 0xf75f042e, 0x6434bb6a, 0xb29e77d8, 0x19be4fd9,
+ 0x76443243, 0x9dd72645, 0x694cef43, 0x89c2efd5, 0x5f1c5058, 0x46c6e45b, 0xe1391b40, 0x77ccefd5,
+ 0x472e5a6d, 0x85709553, 0xdd4f5d4c, 0x64ef5a46, 0x7f0ae502, 0xcf08d850, 0x3460042e, 0xeafa2d42,
+ 0x793c9044, 0x9d094746, 0x1ab9b153, 0xbfe9a5bc, 0x34771fb0, 0xb7722e32, 0x1168964b, 0x19b06ab8,
+ 0x19243b25, 0x13188045, 0xb4070905, 0x728ebb5d, 0x44f24ac8, 0xa317fead, 0x642f6a57, 0x3d951f32,
+ 0x3d312e4e, 0xfac4d048, 0xefc4dd50, 0x52b9f1c7, 0xc14d3cc3, 0x0219ea44, 0x3b79d058, 0xfa217242,
+ 0x39c80647, 0xfb697252, 0x1d495a42, 0x0aa81f4e, 0x58249ab8, 0xe6a8e6c3, 0x2bc4dad8, 0x85963c6c,
+ 0xa4ce09b0, 0x2005f536, 0x5cc2703e, 0x1992de43, 0x74e86b4c, 0xe7085653, 0xf5e15a51, 0xb4872b60,
+ 0x29e2b162, 0xa07ea053, 0x8229fd18, 0x4562ec4d, 0x8dec814e, 0x36cfa4cf, 0x96461032, 0x3c8770de,
+ 0xd10a1f5f, 0x95934641, 0x97cd65d0, 0x2e35324a, 0x2566ba1f, 0x1ca1a9d1, 0xb808b8d5, 0xf9a24a5d,
+ 0xafc8d431, 0xe4b8d9b2, 0x0f5321b2, 0x330bc658, 0x74b347ce, 0x972babd5, 0x044f7d4f, 0x06562f4e,
+ 0x8b8d3c6c, 0x3507c658, 0xe4174e4d, 0xf1c009b0, 0x52249ab8, 0x27211772, 0xf6a9ba59, 0x7a391b40,
+ 0x855dc6c0, 0x291f20b2, 0xe29bc345, 0x90963c6c, 0x0af70732, 0x4242a91f, 0x4c531d48, 0xa32df948,
+ 0x627e3044, 0x65be1f54, 0x1a0cbf83, 0x6a443532, 0x8d5f1955, 0xbafa8132, 0x3534bdd5, 0xca019dd9,
+ 0x8a0d9332, 0x5584e7d8, 0x7cd1f25e, 0xeabe3fb2, 0x2945d0d1, 0x46415718, 0x70d6042e, 0x99eb76d0,
+ 0x9ece09b0, 0xb3777418, 0x5e5e91d9, 0x237a3ab0, 0xf512b62e, 0x45dec347, 0x59b7f862, 0x4c443b25,
+ 0x3cc6484b, 0x9a8ec6d1, 0x021eea44, 0xc9483944, 0xfd567e32, 0xfd204bb2, 0xc5330bcc, 0x5202894e,
+ 0xf9e309b0, 0x4cc17557, 0xdb9064ae, 0xe19e77d8, 0x25857f60, 0xeb4a15ad, 0x1f47f554, 0xea4472d9,
+ 0xd20de593, 0xf5733b25, 0x11892b54, 0x5729d35f, 0xe6188cd1, 0x488b132e, 0x541c534a, 0xa8e854ae,
+ 0xa255a66c, 0x33688763, 0xc6629ac6, 0xc20a6265, 0xcd92a059, 0x72029d3b, 0x4c298f5e, 0x51452e4e,
+ 0xbb065058, 0x15fd2dcc, 0xf40c135e, 0x615a0bad, 0x0c6a6805, 0x4971a7ad, 0x17f2a5d5, 0xf8babf47,
+ 0xb61f50ad, 0x4e1451b1, 0xf72d9252, 0x5c2abe58, 0xbd987c61, 0x084ae5cf, 0x20781fb0, 0x38b0f160,
+ 0x18aac705, 0x14f86dc1, 0x5556f481, 0x0a36c144, 0xeb446e4c, 0x2c1c0d6c, 0xbd0ff860, 0x869f92db,
+ 0x36c94f4c, 0x05502444, 0x148fe55b, 0xd5301e59, 0xd57a8f45, 0x110dc04a, 0x8670fc36, 0xee733b25,
+ 0xca56f481, 0x2a5c3bae, 0x844b0905, 0x1e51fe53, 0x0241c244, 0x59c0614e, 0x94e70a55, 0x7312fead,
+ 0xb735be44, 0xa55d0905, 0x2f63962e, 0x14a4e15b, 0x63f8f05c, 0x62d0d262, 0x3cab41ad, 0x87f1b1cb,
+ 0x018da6b8, 0xb3967dd5, 0xcb56f481, 0x685ad718, 0x3b4aeeca, 0x8d106bc1, 0x51180905, 0x72660f48,
+ 0x1521a243, 0x5b56f481, 0x6390e560, 0xdd61464e, 0x58353b25, 0x553fc062, 0x27c45d59, 0xacc62e4e,
+ 0x0d5a1cd9, 0x7f65f442, 0xbdeef660, 0xf1bd1855, 0xf8473cae, 0x13b120b2, 0x442440d0, 0x53fd4352,
+ 0xa305fc57, 0x458be84d, 0x639ce1c3, 0xebaaee47, 0x95e2c247, 0xf056f481, 0x6256f481, 0x1d87c65e,
+ 0x0a453418, 0x5beb175e, 0xd64f1618, 0xc360795b, 0x2fbf5753, 0xa8c58e53, 0x651cec52, 0x9d37b043,
+ 0x124a9758, 0x5242e4a9, 0x89913c6c, 0x880efe2e, 0x2f2f2f0c, 0x72b26751, 0x2896e46d, 0x80f4166c,
+ 0x320d59ad, 0xc50151d0, 0x11a8aa43, 0xccf56057, 0x5fbad118, 0x4719b151, 0x2b5f4bc0, 0x4d7a4a50,
+ 0xad06e047, 0x62ef5a46, 0x5aebde58, 0xdf7aa66c, 0x851acb50, 0x66b9a559, 0x3e9bb153, 0xcc512f2e,
+ 0xc073b08e, 0xd519be58, 0xe981ea4d, 0x12fd50cb, 0x378739ad, 0x06683cae, 0xa22310b2, 0xc185c705,
+ 0x8741b545, 0xa26c8318, 0x22d5bc43, 0x39201ec0, 0x68581e3e, 0xdc9bcf62, 0xd508cc82, 0xb149675b,
+ 0x4c9609b0, 0x84feb84c, 0x08291e2e, 0xfd2253b2, 0x1fd269c1, 0xc9483932, 0x4d641fb0, 0x7d37c918,
+ 0xa9de20ad, 0x77e2d655, 0x6d421b59, 0xd7668f80, 0xced09b62, 0xa9e5a5bc, 0xa4074e18, 0x60fc5ecc,
+ 0x01300148, 0x68062444, 0xb4224847, 0xed3aa443, 0xb772fb43, 0x9f56f481, 0x220dfd18, 0x8e1c3d6c,
+ 0xc44f09b0, 0x7df2bb73, 0xe22fb844, 0xea534242, 0xb6a755d4, 0xa036654b, 0x138ece5b, 0xda65d3c3,
+ 0x955871bc, 0x792124b0, 0xfc82594c, 0x851d494b, 0x2c7aee47, 0x26af46b8, 0x1416252e, 0xa8abb944,
+ 0x36c49d25, 0x674f645d, 0x363646b8, 0x9e1a2942, 0x66d0c154, 0xc6c2a545, 0x3570f2ad, 0xe7d547c7,
+ 0x7d104932, 0x18cb9c18, 0x1dcfa4cf, 0xd156f481, 0x2a02b91f, 0x3eeb3fa8, 0xcac4175e, 0x34146d42,
+ 0x994c4d46, 0x5666f440, 0x85d6713e, 0x5ecb296c, 0x0ea0ae46, 0x87e69f42, 0xc58409b0, 0x1f3436ae,
+ 0x21dc6a57, 0x4ad1cd42, 0xfb8c1a4c, 0x52d3dab2, 0x3769894b, 0xb52f1c62, 0x3677916d, 0x82b3fe57,
+ 0x493d4ac6, 0x9f963c6c, 0x5d91ff60, 0x458e0dad, 0xa49d0947, 0x491a3e18, 0x4aadcd5b, 0x0e46494b,
+ 0x1d1610ad, 0x1a10af5d, 0x4956f481, 0x207a3eae, 0x77e73244, 0xfa3b8742, 0x3261fc36, 0xfcebf536,
+ 0x1662e836, 0xf655f636, 0xa2dbd0ad, 0x23036693, 0x30448432, 0xa2b03463, 0x30730344, 0x8e4a6882,
+ 0x0c50a1cb, 0xc8d8c06b, 0xc9cd6191, 0xf443db50, 0xa9553c50, 0x23145847, 0xc35da66c, 0x29c12a60,
+ 0x55c2b447, 0x7434f75c, 0x61660640, 0xde2a7018, 0xc639494c, 0x1c306fce, 0x19b89244, 0xd29a6462,
+ 0x462cd1b2, 0x29902f44, 0x2817fa53, 0x21a30905, 0x7777ae46, 0x288443a1, 0x7bee5148, 0xc2a8b043,
+ 0xf5c3d35f, 0x2311ef84, 0x57de08a4, 0x6b221bb2, 0xf2625846, 0x4b9e09b0, 0xa24f880e, 0x22b11447,
+ 0xb3a0c744, 0x919e77d8, 0xec8b64ae, 0xff5c8d45, 0x7b15b484, 0x32679a5f, 0xba80b62e, 0x05c25c61,
+ 0x60014746, 0x5e8fb04c, 0xe67c0905, 0x4329c658, 0xac8fe555, 0xf875e647, 0x67406386, 0x35ceea18,
+ 0xbb79484b, 0xd7b9fa62, 0x238209b0, 0x208a1d32, 0x9630995e, 0x039c1318, 0x6e48006c, 0x60582344,
+ 0xadbb0150, 0x853fd462, 0x03772e4e, 0x652ce960, 0x49b630ad, 0x9993af43, 0x3735b34b, 0x548a07d9,
+ 0x55a44aad, 0xa23d1bcc, 0xfdbb2f4e, 0x530b24a0, 0x0a44b451, 0x6827c657, 0x1f66494b, 0x4e680a47,
+ 0x77e7b747, 0xa5eb3fa8, 0x6649764a, 0xd4e76c4b, 0x2c691fb0, 0xf1292e44, 0xc6d6c774, 0x85d23775,
+ 0x28275f4d, 0x259ae46d, 0x02424e81, 0x5f16be58, 0xe707c658, 0x49eae5c7, 0xd5d147ad, 0x9a7abdc3,
+ 0xe8ac7fc7, 0x84ec3aae, 0xc24942d0, 0x294aa318, 0x08ac3d18, 0x8894042e, 0xb24609b0, 0x9bcaab58,
+ 0xc400f712, 0xd5c512b8, 0x2c02cc62, 0x25080fd8, 0xed74a847, 0x18a5ec5e, 0x9850ec6d, 0xf8909758,
+ 0x7f56f481, 0x4496f23c, 0xae27784f, 0xcb7cd93e, 0x06e32860, 0x50b9a84f, 0x3660434a, 0x09161f5f,
+ 0x900486bc, 0x08055459, 0xe7ec1017, 0x7e39494c, 0x4f443b25, 0x14751a8a, 0x717d03d4, 0xbd0e24d8,
+ 0x054b6f56, 0x854c496c, 0xd92a454a, 0xc39bd054, 0x6093614b, 0x9dbad754, 0x5bf0604a, 0x99f22305
};
void DumpAddresses()
@@ -1523,16 +1529,26 @@ void ThreadOpenAddedConnections2(void* parg)
{
printf("ThreadOpenAddedConnections started\n");
- if (mapArgs.count("-addnode") == 0)
- return;
+ {
+ LOCK(cs_vAddedNodes);
+ vAddedNodes = mapMultiArgs["-addnode"];
+ }
if (HaveNameProxy()) {
while(!fShutdown) {
- BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) {
+ list<string> lAddresses(0);
+ {
+ LOCK(cs_vAddedNodes);
+ BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ lAddresses.push_back(strAddNode);
+ }
+ BOOST_FOREACH(string& strAddNode, lAddresses) {
CAddress addr;
CSemaphoreGrant grant(*semOutbound);
OpenNetworkConnection(addr, &grant, strAddNode.c_str());
Sleep(500);
+ if (fShutdown)
+ return;
}
vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
Sleep(120000); // Retry every 2 minutes
@@ -1541,41 +1557,47 @@ void ThreadOpenAddedConnections2(void* parg)
return;
}
- vector<vector<CService> > vservAddressesToAdd(0);
- BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
+ for (unsigned int i = 0; true; i++)
{
- vector<CService> vservNode(0);
- if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
+ list<string> lAddresses(0);
+ {
+ LOCK(cs_vAddedNodes);
+ BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ lAddresses.push_back(strAddNode);
+ }
+
+ list<vector<CService> > lservAddressesToAdd(0);
+ BOOST_FOREACH(string& strAddNode, lAddresses)
{
- vservAddressesToAdd.push_back(vservNode);
+ vector<CService> vservNode(0);
+ if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
{
- LOCK(cs_setservAddNodeAddresses);
- BOOST_FOREACH(CService& serv, vservNode)
- setservAddNodeAddresses.insert(serv);
+ lservAddressesToAdd.push_back(vservNode);
+ {
+ LOCK(cs_setservAddNodeAddresses);
+ BOOST_FOREACH(CService& serv, vservNode)
+ setservAddNodeAddresses.insert(serv);
+ }
}
}
- }
- loop
- {
- vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
// Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
- for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
+ for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
BOOST_FOREACH(CService& addrNode, *(it))
if (pnode->addr == addrNode)
{
- it = vservConnectAddresses.erase(it);
+ it = lservAddressesToAdd.erase(it);
it--;
break;
}
}
- BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
+ BOOST_FOREACH(vector<CService>& vserv, lservAddressesToAdd)
{
CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(CAddress(*(vserv.begin())), &grant);
+ OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
Sleep(500);
if (fShutdown)
return;
diff --git a/src/net.h b/src/net.h
index 99f41161b1..14e12aa102 100644
--- a/src/net.h
+++ b/src/net.h
@@ -102,6 +102,9 @@ extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
extern std::map<CInv, int64> mapAlreadyAskedFor;
+extern std::vector<std::string> vAddedNodes;
+extern CCriticalSection cs_vAddedNodes;
+
diff --git a/src/noui.cpp b/src/noui.cpp
index 302d059291..c0e00c4715 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -9,7 +9,7 @@
#include <string>
-static int noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
+static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
std::string strCaption;
// Check for usage of predefined caption
@@ -29,7 +29,7 @@ static int noui_ThreadSafeMessageBox(const std::string& message, const std::stri
printf("%s: %s\n", strCaption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
- return 4;
+ return false;
}
static bool noui_ThreadSafeAskFee(int64 /*nFeeRequired*/)
diff --git a/src/qt/aboutdialog.cpp b/src/qt/aboutdialog.cpp
index 0b98befe8d..755413b2bb 100644
--- a/src/qt/aboutdialog.cpp
+++ b/src/qt/aboutdialog.cpp
@@ -1,14 +1,20 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
+
#include "clientmodel.h"
-#include "version.h"
+// Copyright year (2009-this)
+// Todo: update this when changing our copyright comments in the source
+const int ABOUTDIALOG_COPYRIGHT_YEAR = 2013;
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
+
+ // Set current copyright year
+ ui->copyrightLabel->setText(tr("Copyright") + QString(" &copy; ") + tr("2009-%1 The Bitcoin developers").arg(ABOUTDIALOG_COPYRIGHT_YEAR));
}
void AboutDialog::setModel(ClientModel *model)
diff --git a/src/qt/aboutdialog.h b/src/qt/aboutdialog.h
index 2ed9e9e7c4..33b1437674 100644
--- a/src/qt/aboutdialog.h
+++ b/src/qt/aboutdialog.h
@@ -18,6 +18,7 @@ public:
~AboutDialog();
void setModel(ClientModel *model);
+
private:
Ui::AboutDialog *ui;
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index e5526a6c09..afd8d71a0e 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -34,23 +34,27 @@ Q_IMPORT_PLUGIN(qtaccessiblewidgets)
static BitcoinGUI *guiref;
static QSplashScreen *splashref;
-static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
+static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
// Message from network thread
if(guiref)
{
bool modal = (style & CClientUIInterface::MODAL);
+ bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button
QMetaObject::invokeMethod(guiref, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
- Q_ARG(unsigned int, style));
+ Q_ARG(unsigned int, style),
+ Q_ARG(bool*, &ret));
+ return ret;
}
else
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
+ return false;
}
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 9cd22ed297..f1bf5f5880 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -67,7 +67,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
aboutQtAction(0),
trayIcon(0),
notificator(0),
- rpcConsole(0)
+ rpcConsole(0),
+ prevBlocks(0)
{
resize(850, 550);
setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet"));
@@ -527,52 +528,17 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
importText = tr("Reindexing blocks on disk...");
}
- if(count < nTotalBlocks)
- {
- int nRemainingBlocks = nTotalBlocks - count;
- float nPercentageDone = count / (nTotalBlocks * 0.01f);
-
- progressBarLabel->setText(importText);
- progressBarLabel->setVisible(true);
- progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
- progressBar->setMaximum(nTotalBlocks);
- progressBar->setValue(count);
- progressBar->setVisible(true);
-
- tooltip = tr("Processed %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
- }
- else
- {
- progressBarLabel->setVisible(false);
-
- progressBar->setVisible(false);
- tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
- }
-
QDateTime lastBlockDate = clientModel->getLastBlockDate();
- int secs = lastBlockDate.secsTo(QDateTime::currentDateTime());
- QString text;
+ QDateTime currentDate = QDateTime::currentDateTime();
+ int secs = lastBlockDate.secsTo(currentDate);
- // Represent time from last generated block in human readable text
- if(secs <= 0)
- {
- // Fully up to date. Leave text empty.
- }
- else if(secs < 60)
- {
- text = tr("%n second(s) ago","",secs);
- }
- else if(secs < 60*60)
- {
- text = tr("%n minute(s) ago","",secs/60);
- }
- else if(secs < 24*60*60)
+ if(count < nTotalBlocks)
{
- text = tr("%n hour(s) ago","",secs/(60*60));
+ tooltip = tr("Processed %1 of %2 (estimated) blocks of transaction history.").arg(count).arg(nTotalBlocks);
}
else
{
- text = tr("%n day(s) ago","",secs/(60*60*24));
+ tooltip = tr("Processed %1 blocks of transaction history.").arg(count);
}
// Set icon state: spinning if catching up, tick otherwise
@@ -582,20 +548,46 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
overviewPage->showOutOfSyncWarning(false);
+
+ progressBarLabel->setVisible(false);
+ progressBar->setVisible(false);
}
else
{
+ // Represent time from last generated block in human readable text
+ QString timeBehindText;
+ if(secs < 48*60*60)
+ {
+ timeBehindText = tr("%n hour(s)","",secs/(60*60));
+ }
+ else if(secs < 14*24*60*60)
+ {
+ timeBehindText = tr("%n day(s)","",secs/(24*60*60));
+ }
+ else
+ {
+ timeBehindText = tr("%n week(s)","",secs/(7*24*60*60));
+ }
+
+ progressBarLabel->setText(importText);
+ progressBarLabel->setVisible(true);
+ progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
+ progressBar->setMaximum(1000000000);
+ progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5);
+ progressBar->setVisible(true);
+
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
labelBlocksIcon->setMovie(syncIconMovie);
- syncIconMovie->start();
+ if(count != prevBlocks)
+ syncIconMovie->jumpToNextFrame();
+ prevBlocks = count;
overviewPage->showOutOfSyncWarning(true);
- }
- if(!text.isEmpty())
- {
tooltip += QString("<br>");
- tooltip += tr("Last received block was generated %1.").arg(text);
+ tooltip += tr("Last received block was generated %1 ago.").arg(timeBehindText);
+ tooltip += QString("<br>");
+ tooltip += tr("Transactions after this will not yet be visible.");
}
// Don't word-wrap this (fixed-width) tooltip
@@ -606,7 +598,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
progressBar->setToolTip(tooltip);
}
-void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style)
+void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
{
QString strTitle = tr("Bitcoin") + " - ";
// Default to information icon
@@ -646,7 +638,9 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
buttons = QMessageBox::Ok;
QMessageBox mBox((QMessageBox::Icon)nMBoxIcon, strTitle, message, buttons);
- mBox.exec();
+ int r = mBox.exec();
+ if (ret != NULL)
+ *ret = r == QMessageBox::Ok;
}
else
notificator->notify((Notificator::Class)nNotifyIcon, strTitle, message);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index b7afdb1c8c..8ce0335bcd 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -98,6 +98,8 @@ private:
RPCConsole *rpcConsole;
QMovie *syncIconMovie;
+ /** Keep track of previous number of blocks, to detect progress */
+ int prevBlocks;
/** Create the main UI actions. */
void createActions();
@@ -126,8 +128,9 @@ public slots:
@param[in] message the displayed text
@param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes)
@see CClientUIInterface::MessageBoxFlags
+ @param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only)
*/
- void message(const QString &title, const QString &message, unsigned int style);
+ void message(const QString &title, const QString &message, unsigned int style, bool *ret = NULL);
/** Asks the user whether to pay the transaction fee or to cancel the transaction.
It is currently not possible to pass a return value to another thread through
BlockingQueuedConnection, so an indirected pointer is used.
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 92a511adb9..2c3d859c82 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -100,6 +100,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Connect to a node to retrieve peer addresses,
QT_TRANSLATE_NOOP("bitcoin-core", "Discover own IP address (default: 1 when listening and no -externalip)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Don't generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"),
@@ -109,13 +110,24 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Transaction creation failed!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: could not start node"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: system error: "),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block info"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to sync block index"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block index"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block info"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write file info"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to coin database"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write transaction index"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data"),
QT_TRANSLATE_NOOP("bitcoin-core", "Fee per KB to add to transactions you send"),
QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using DNS lookup (default: 1 unless -connect)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Find peers using internet relay chat (default: 0)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins"),
QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"),
-QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 2500, 0 = all)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "How 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", "Importing blocks from block database..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"),
@@ -163,6 +175,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specify connection timeout in milliseconds (d
QT_TRANSLATE_NOOP("bitcoin-core", "Specify data directory"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify pid file (default: bitcoind.pid)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"),
+QT_TRANSLATE_NOOP("bitcoin-core", "System error: "),
QT_TRANSLATE_NOOP("bitcoin-core", "This help message"),
QT_TRANSLATE_NOOP("bitcoin-core", "Threshold for disconnecting misbehaving peers (default: 100)"),
QT_TRANSLATE_NOOP("bitcoin-core", "To use the %s option"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 12bd989338..858fbe241f 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -6,6 +6,7 @@
#include "alert.h"
#include "main.h"
+#include "checkpoints.h"
#include "ui_interface.h"
#include <QDateTime>
@@ -48,7 +49,15 @@ int ClientModel::getNumBlocksAtStartup()
QDateTime ClientModel::getLastBlockDate() const
{
- return QDateTime::fromTime_t(pindexBest->GetBlockTime());
+ if (pindexBest)
+ return QDateTime::fromTime_t(pindexBest->GetBlockTime());
+ else
+ return QDateTime::fromTime_t(1231006505); // Genesis block's time
+}
+
+double ClientModel::getVerificationProgress() const
+{
+ return Checkpoints::GuessVerificationProgress(pindexBest);
}
void ClientModel::updateTimer()
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 1afccb7859..a3fe92048c 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -34,6 +34,7 @@ public:
int getNumBlocks() const;
int getNumBlocksAtStartup();
+ double getVerificationProgress() const;
QDateTime getLastBlockDate() const;
//! Return true if client connected to testnet
diff --git a/src/qt/forms/aboutdialog.ui b/src/qt/forms/aboutdialog.ui
index b59c2445de..80768f89b0 100644
--- a/src/qt/forms/aboutdialog.ui
+++ b/src/qt/forms/aboutdialog.ui
@@ -91,7 +91,10 @@
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
- <string>Copyright © 2009-2012 The Bitcoin developers</string>
+ <string notr="true">Copyright &amp;copy; 2009-YYYY The Bitcoin developers</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 405ba396b7..92417834ec 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -2,7 +2,7 @@
#define GUICONSTANTS_H
/* Milliseconds between model updates */
-static const int MODEL_UPDATE_DELAY = 500;
+static const int MODEL_UPDATE_DELAY = 250;
/* AskPassphraseDialog -- Maximum passphrase length */
static const int MAX_PASSPHRASE_SIZE = 1024;
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 4895e9ba4e..39062d0a2c 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -15,12 +15,7 @@
<translation>&lt;b&gt;Bitcoin&lt;/b&gt; version</translation>
</message>
<message>
- <location line="+41"/>
- <source>Copyright © 2009-2012 The Bitcoin developers</source>
- <translation>Copyright © 2009-2012 The Bitcoin developers</translation>
- </message>
- <message>
- <location line="+13"/>
+ <location line="+57"/>
<source>
This is experimental software.
@@ -34,6 +29,16 @@ Distributed under the MIT/X11 software license, see the accompanying file COPYIN
This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) and cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard.</translation>
</message>
+ <message>
+ <location filename="../aboutdialog.cpp" line="+17"/>
+ <source>Copyright</source>
+ <translation>Copyright</translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>2009-%1 The Bitcoin developers</source>
+ <translation>2009-%1 The Bitcoin developers</translation>
+ </message>
</context>
<context>
<name>AddressBookPage</name>
@@ -713,7 +718,7 @@ Address: %4
<context>
<name>ClientModel</name>
<message>
- <location filename="../clientmodel.cpp" line="+86"/>
+ <location filename="../clientmodel.cpp" line="+89"/>
<source>Network Alert</source>
<translation>Network Alert</translation>
</message>
@@ -2174,12 +2179,12 @@ Address: %4
<translation>Bitcoin version</translation>
</message>
<message>
- <location line="+83"/>
+ <location line="+96"/>
<source>Usage:</source>
<translation>Usage:</translation>
</message>
<message>
- <location line="-23"/>
+ <location line="-24"/>
<source>Send command to -server or bitcoind</source>
<translation>Send command to -server or bitcoind</translation>
</message>
@@ -2214,12 +2219,12 @@ Address: %4
<translation>Generate coins</translation>
</message>
<message>
- <location line="-15"/>
+ <location line="-27"/>
<source>Don&apos;t generate coins</source>
<translation>Don&apos;t generate coins</translation>
</message>
<message>
- <location line="+62"/>
+ <location line="+74"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
@@ -2239,22 +2244,22 @@ Address: %4
<translation>Maintain at most &lt;n&gt; connections to peers (default: 125)</translation>
</message>
<message>
- <location line="-35"/>
+ <location line="-47"/>
<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="+66"/>
+ <location line="+78"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+3"/>
<source>Threshold for disconnecting misbehaving peers (default: 100)</source>
<translation>Threshold for disconnecting misbehaving peers (default: 100)</translation>
</message>
<message>
- <location line="-117"/>
+ <location line="-130"/>
<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>
@@ -2274,17 +2279,17 @@ Address: %4
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+75"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
<message>
- <location line="+31"/>
+ <location line="+32"/>
<source>Use the test network</source>
<translation>Use the test network</translation>
</message>
<message>
- <location line="-93"/>
+ <location line="-106"/>
<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>
@@ -2405,6 +2410,11 @@ If the file does not exist, create it with owner-readable-only file permissions.
</message>
<message>
<location line="+3"/>
+ <source>Error initializing block database</source>
+ <translation>Error initializing block database</translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Error loading block database</source>
<translation>Error loading block database</translation>
</message>
@@ -2425,16 +2435,76 @@ If the file does not exist, create it with owner-readable-only file permissions.
</message>
<message>
<location line="+2"/>
+ <source>Error: system error: </source>
+ <translation>Error: system error: </translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Failed to read block info</source>
+ <translation>Failed to read block info</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to read block</source>
+ <translation>Failed to read block</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to sync block index</source>
+ <translation>Failed to sync block index</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write block index</source>
+ <translation>Failed to write block index</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write block info</source>
+ <translation>Failed to write block info</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write block</source>
+ <translation>Failed to write block</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write file info</source>
+ <translation>Failed to write file info</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write to coin database</source>
+ <translation>Failed to write to coin database</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write transaction index</source>
+ <translation>Failed to write transaction index</translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Failed to write undo data</source>
+ <translation>Failed to write undo data</translation>
+ </message>
+ <message>
<location line="+2"/>
<source>Find peers using DNS lookup (default: 1 unless -connect)</source>
<translation>Find peers using DNS lookup (default: 1 unless -connect)</translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+4"/>
+ <source>How many blocks to check at startup (default: 288, 0 = all)</source>
+ <translation>How many blocks to check at startup (default: 288, 0 = all)</translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>How thorough the block verification is (0-4, default: 3)</source>
<translation>How thorough the block verification is (0-4, default: 3)</translation>
</message>
@@ -2544,7 +2614,12 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Specify connection timeout in milliseconds (default: 5000)</translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+4"/>
+ <source>System error: </source>
+ <translation>System error: </translation>
+ </message>
+ <message>
+ <location line="+10"/>
<source>Use UPnP to map the listening port (default: 0)</source>
<translation>Use UPnP to map the listening port (default: 0)</translation>
</message>
@@ -2584,32 +2659,32 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>wallet.dat corrupt, salvage failed</translation>
</message>
<message>
- <location line="-44"/>
+ <location line="-45"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-54"/>
+ <location line="-66"/>
<source>Allow JSON-RPC connections from specified IP address</source>
<translation>Allow JSON-RPC connections from specified IP address</translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+75"/>
<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="-106"/>
+ <location line="-118"/>
<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="+127"/>
+ <location line="+140"/>
<source>Upgrade wallet to latest format</source>
<translation>Upgrade wallet to latest format</translation>
</message>
<message>
- <location line="-15"/>
+ <location line="-16"/>
<source>Set key pool size to &lt;n&gt; (default: 100)</source>
<translation>Set key pool size to &lt;n&gt; (default: 100)</translation>
</message>
@@ -2619,17 +2694,12 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Rescan the block chain for missing wallet transactions</translation>
</message>
<message>
- <location line="-27"/>
- <source>How many blocks to check at startup (default: 2500, 0 = all)</source>
- <translation>How many blocks to check at startup (default: 2500, 0 = all)</translation>
- </message>
- <message>
- <location line="+56"/>
+ <location line="+30"/>
<source>Use OpenSSL (https) for JSON-RPC connections</source>
<translation>Use OpenSSL (https) for JSON-RPC connections</translation>
</message>
<message>
- <location line="-20"/>
+ <location line="-21"/>
<source>Server certificate file (default: server.cert)</source>
<translation>Server certificate file (default: server.cert)</translation>
</message>
@@ -2639,12 +2709,12 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Server private key (default: server.pem)</translation>
</message>
<message>
- <location line="-136"/>
+ <location line="-148"/>
<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="+147"/>
+ <location line="+160"/>
<source>This help message</source>
<translation>This help message</translation>
</message>
@@ -2654,7 +2724,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation>
</message>
<message>
- <location line="-71"/>
+ <location line="-84"/>
<source>Connect through socks proxy</source>
<translation>Connect through socks proxy</translation>
</message>
@@ -2664,12 +2734,12 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
<message>
- <location line="+43"/>
+ <location line="+55"/>
<source>Loading addresses...</source>
<translation>Loading addresses...</translation>
</message>
<message>
- <location line="-25"/>
+ <location line="-36"/>
<source>Error loading wallet.dat: Wallet corrupted</source>
<translation>Error loading wallet.dat: Wallet corrupted</translation>
</message>
@@ -2679,7 +2749,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Error loading wallet.dat: Wallet requires newer version of Bitcoin</translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+86"/>
<source>Verifying block database integrity...</source>
<translation>Verifying block database integrity...</translation>
</message>
@@ -2694,17 +2764,17 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Wallet needed to be rewritten: restart Bitcoin to complete</translation>
</message>
<message>
- <location line="-78"/>
+ <location line="-90"/>
<source>Error loading wallet.dat</source>
<translation>Error loading wallet.dat</translation>
</message>
<message>
- <location line="+20"/>
+ <location line="+31"/>
<source>Invalid -proxy address: &apos;%s&apos;</source>
<translation>Invalid -proxy address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+48"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
@@ -2714,7 +2784,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Unknown -socks proxy version requested: %i</translation>
</message>
<message>
- <location line="-76"/>
+ <location line="-89"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -2724,17 +2794,17 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Cannot resolve -externalip address: &apos;%s&apos;</translation>
</message>
<message>
- <location line="+31"/>
+ <location line="+43"/>
<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>
<message>
- <location line="-15"/>
+ <location line="-26"/>
<source>Error: could not start node</source>
<translation>Error: could not start node</translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+27"/>
<source>Invalid amount</source>
<translation>Invalid amount</translation>
</message>
@@ -2749,7 +2819,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Loading block index...</translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-57"/>
<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>
@@ -2759,7 +2829,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Unable to bind to %s on this computer. Bitcoin is probably already running.</translation>
</message>
<message>
- <location line="+54"/>
+ <location line="+66"/>
<source>Find peers using internet relay chat (default: 0)</source>
<translation>Find peers using internet relay chat (default: 0)</translation>
</message>
@@ -2774,7 +2844,7 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-40"/>
+ <location line="-52"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -2789,27 +2859,27 @@ If the file does not exist, create it with owner-readable-only file permissions.
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+50"/>
+ <location line="+62"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-44"/>
+ <location line="-56"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+66"/>
+ <location line="+79"/>
<source>To use the %s option</source>
<translation>To use the %s option</translation>
</message>
<message>
- <location line="-61"/>
+ <location line="-73"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message>
- <location line="-28"/>
+ <location line="-29"/>
<source>You must set rpcpassword=&lt;password&gt; in the configuration file:
%s
If the file does not exist, create it with owner-readable-only file permissions.</source>
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 8028190b82..628dca1591 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -113,7 +113,7 @@ FreedesktopImage::FreedesktopImage(const QImage &img):
{
// Convert 00xAARRGGBB to RGBA bytewise (endian-independent) format
QImage tmp = img.convertToFormat(QImage::Format_ARGB32);
- const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.constBits());
+ const uint32_t *data = reinterpret_cast<const uint32_t*>(tmp.bits());
unsigned int num_pixels = width * height;
image.resize(num_pixels * BYTES_PER_PIXEL);
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 778e0acbd2..fddda8b5f4 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -307,7 +307,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
}
entry.push_back(Pair("depends", deps));
- int index_in_template = &tx - pblock->vtx.data();
+ int index_in_template = i - 1;
entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template]));
entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template]));
@@ -365,9 +365,10 @@ Value submitblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
}
- bool fAccepted = ProcessBlock(NULL, &pblock);
+ CValidationState state;
+ bool fAccepted = ProcessBlock(state, NULL, &pblock);
if (!fAccepted)
- return "rejected";
+ return "rejected"; // TODO: report validation state
return Value::null;
}
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 491297eb1d..4db3be9319 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -65,3 +65,137 @@ Value getpeerinfo(const Array& params, bool fHelp)
return ret;
}
+Value addnode(const Array& params, bool fHelp)
+{
+ string strCommand;
+ if (params.size() == 2)
+ strCommand = params[1].get_str();
+ if (fHelp || params.size() != 2 ||
+ (strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
+ throw runtime_error(
+ "addnode <node> <add|remove|onetry>\n"
+ "Attempts add or remove <node> from the addnode list or try a connection to <node> once.");
+
+ string strNode = params[0].get_str();
+
+ if (strCommand == "onetry")
+ {
+ CAddress addr;
+ ConnectNode(addr, strNode.c_str());
+ return Value::null;
+ }
+
+ LOCK(cs_vAddedNodes);
+ vector<string>::iterator it = vAddedNodes.begin();
+ for(; it != vAddedNodes.end(); it++)
+ if (strNode == *it)
+ break;
+
+ if (strCommand == "add")
+ {
+ if (it != vAddedNodes.end())
+ throw JSONRPCError(-23, "Error: Node already added");
+ vAddedNodes.push_back(strNode);
+ }
+ else if(strCommand == "remove")
+ {
+ if (it == vAddedNodes.end())
+ throw JSONRPCError(-24, "Error: Node has not been added.");
+ vAddedNodes.erase(it);
+ }
+
+ return Value::null;
+}
+
+Value getaddednodeinfo(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "getaddednodeinfo <dns> [node]\n"
+ "Returns information about the given added node, or all added nodes\n"
+ "(note that onetry addnodes are not listed here)\n"
+ "If dns is false, only a list of added nodes will be provided,\n"
+ "otherwise connected information will also be available.");
+
+ bool fDns = params[0].get_bool();
+
+ list<string> laddedNodes(0);
+ if (params.size() == 1)
+ {
+ LOCK(cs_vAddedNodes);
+ BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ laddedNodes.push_back(strAddNode);
+ }
+ else
+ {
+ string strNode = params[1].get_str();
+ LOCK(cs_vAddedNodes);
+ BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ if (strAddNode == strNode)
+ {
+ laddedNodes.push_back(strAddNode);
+ break;
+ }
+ if (laddedNodes.size() == 0)
+ throw JSONRPCError(-24, "Error: Node has not been added.");
+ }
+
+ if (!fDns)
+ {
+ Object ret;
+ BOOST_FOREACH(string& strAddNode, laddedNodes)
+ ret.push_back(Pair("addednode", strAddNode));
+ return ret;
+ }
+
+ Array ret;
+
+ list<pair<string, vector<CService> > > laddedAddreses(0);
+ BOOST_FOREACH(string& strAddNode, laddedNodes)
+ {
+ vector<CService> vservNode(0);
+ if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
+ laddedAddreses.push_back(make_pair(strAddNode, vservNode));
+ else
+ {
+ Object obj;
+ obj.push_back(Pair("addednode", strAddNode));
+ obj.push_back(Pair("connected", false));
+ Array addresses;
+ obj.push_back(Pair("addresses", addresses));
+ }
+ }
+
+ LOCK(cs_vNodes);
+ for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
+ {
+ Object obj;
+ obj.push_back(Pair("addednode", it->first));
+
+ Array addresses;
+ bool fConnected = false;
+ BOOST_FOREACH(CService& addrNode, it->second)
+ {
+ bool fFound = false;
+ Object node;
+ node.push_back(Pair("address", addrNode.ToString()));
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->addr == addrNode)
+ {
+ fFound = true;
+ fConnected = true;
+ node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
+ break;
+ }
+ if (!fFound)
+ node.push_back(Pair("connected", "false"));
+ addresses.push_back(node);
+ }
+ obj.push_back(Pair("connected", fConnected));
+ obj.push_back(Pair("addresses", addresses));
+ ret.push_back(obj);
+ }
+
+ return ret;
+}
+
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 09fbaa30cd..bbaf40c735 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -421,7 +421,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
Object prevOut = p.get_obj();
- RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
+ RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
uint256 txid = ParseHashO(prevOut, "txid");
@@ -450,12 +450,16 @@ Value signrawtransaction(const Array& params, bool fHelp)
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
- Value v = find_value(prevOut, "redeemScript");
- if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && !(v == Value::null))
+ if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
{
- vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
- CScript redeemScript(rsData.begin(), rsData.end());
- tempKeystore.AddCScript(redeemScript);
+ RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
+ Value v = find_value(prevOut, "redeemScript");
+ if (!(v == Value::null))
+ {
+ vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
+ CScript redeemScript(rsData.begin(), rsData.end());
+ tempKeystore.AddCScript(redeemScript);
+ }
}
}
}
@@ -546,8 +550,9 @@ Value sendrawtransaction(const Array& params, bool fHelp)
fHave = view.GetCoins(hashTx, existingCoins);
if (!fHave) {
// push to local node
- if (!tx.AcceptToMemoryPool())
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
+ CValidationState state;
+ if (!tx.AcceptToMemoryPool(state, true, false))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
}
}
if (fHave) {
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 90a68f560a..21eb2fd1aa 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -75,6 +75,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight));
+ obj.push_back(Pair("timeoffset", (boost::int64_t)GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index bc2a05a6b3..af284653dd 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -73,7 +73,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
txFirst.push_back(new CTransaction(pblock->vtx[0]));
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nNonce = blockinfo[i].nonce;
- assert(ProcessBlock(NULL, pblock));
+ CValidationState state;
+ BOOST_CHECK(ProcessBlock(state, NULL, pblock));
+ BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash();
}
delete pblocktemplate;
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index f75b762f1f..1116507a34 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -28,7 +28,7 @@ struct TestingSetup {
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
- LoadBlockIndex();
+ InitBlockIndex();
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
pwalletMain->LoadWallet(fFirstRun);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 23837c6c15..f44d46fdb8 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -66,7 +66,9 @@ BOOST_AUTO_TEST_CASE(tx_valid)
CTransaction tx;
stream >> tx;
- BOOST_CHECK_MESSAGE(tx.CheckTransaction(), strTest);
+ CValidationState state;
+ BOOST_CHECK_MESSAGE(tx.CheckTransaction(state), strTest);
+ BOOST_CHECK(state.IsValid());
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
@@ -133,7 +135,8 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
CTransaction tx;
stream >> tx;
- fValid = tx.CheckTransaction();
+ CValidationState state;
+ fValid = tx.CheckTransaction(state) && state.IsValid();
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
@@ -159,11 +162,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
CTransaction tx;
stream >> tx;
- BOOST_CHECK_MESSAGE(tx.CheckTransaction(), "Simple deserialized transaction should be valid.");
+ CValidationState state;
+ BOOST_CHECK_MESSAGE(tx.CheckTransaction(state) && state.IsValid(), "Simple deserialized transaction should be valid.");
// Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]);
- BOOST_CHECK_MESSAGE(!tx.CheckTransaction(), "Transaction with duplicate txins should be invalid.");
+ BOOST_CHECK_MESSAGE(!tx.CheckTransaction(state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
}
//
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index f56969cba6..1b0ccad511 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -261,4 +261,66 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_CHECK(!IsHex("0x0000"));
}
+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);
+
+ for (int mod=2;mod<11;mod++)
+ {
+ int mask = 1;
+ // Really rough binomal confidence approximation.
+ int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.);
+ //mask is 2^ceil(log2(mod))-1
+ while(mask<mod-1)mask=(mask<<1)+1;
+
+ count = 0;
+ //How often does it get a zero from the uniform range [0,mod)?
+ for (i=0;i<10000;i++)
+ {
+ uint32_t rval;
+ do{
+ rval=insecure_rand()&mask;
+ }while(rval>=(uint32_t)mod);
+ count += rval==0;
+ }
+ 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/txdb.cpp b/src/txdb.cpp
index ca4e6c9bd8..ae7aceb7f1 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -19,7 +19,7 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
batch.Write('B', hash);
}
-CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "coins", nCacheSize, fMemory, fWipe) {
+CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}
bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
@@ -64,7 +64,7 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockI
return db.WriteBatch(batch);
}
-CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blktree", nCacheSize, fMemory, fWipe) {
+CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
}
bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
diff --git a/src/txdb.h b/src/txdb.h
index 47496eddba..f59fc5da86 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -8,7 +8,7 @@
#include "main.h"
#include "leveldb.h"
-/** CCoinsView backed by the LevelDB coin database (coins/) */
+/** CCoinsView backed by the LevelDB coin database (chainstate/) */
class CCoinsViewDB : public CCoinsView
{
protected:
@@ -25,7 +25,7 @@ public:
bool GetStats(CCoinsStats &stats);
};
-/** Access to the block database (blktree/) */
+/** Access to the block database (blocks/index/) */
class CBlockTreeDB : public CLevelDB
{
public:
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 703e15f095..f7dbe20894 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -68,7 +68,7 @@ public:
};
/** Show message box. */
- boost::signals2::signal<void (const std::string& message, const std::string& caption, unsigned int style)> ThreadSafeMessageBox;
+ boost::signals2::signal<bool (const std::string& message, const std::string& caption, unsigned int style), boost::signals2::last_value<bool> > ThreadSafeMessageBox;
/** Ask the user whether they want to pay a fee or not. */
boost::signals2::signal<bool (int64 nFeeRequired), boost::signals2::last_value<bool> > ThreadSafeAskFee;
diff --git a/src/util.cpp b/src/util.cpp
index d8f05cb9fd..fc3e846a6b 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -3,6 +3,15 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef WIN32
+// for posix_fallocate
+#ifdef __linux__
+#define _POSIX_C_SOURCE 200112L
+#endif
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
#include "util.h"
#include "sync.h"
#include "version.h"
@@ -1152,9 +1161,46 @@ int GetFilesize(FILE* file)
return nFilesize;
}
+bool TruncateFile(FILE *file, unsigned int length) {
+#if defined(WIN32)
+ return _chsize(_fileno(file), length) == 0;
+#else
+ return ftruncate(fileno(file), length) == 0;
+#endif
+}
+
// this function tries to make a particular range of a file allocated (corresponding to disk space)
// it is advisory, and the range specified in the arguments will never contain live data
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
+#if defined(WIN32)
+ // Windows-specific version
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
+ LARGE_INTEGER nFileSize;
+ int64 nEndPos = (int64)offset + length;
+ nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
+ nFileSize.u.HighPart = nEndPos >> 32;
+ SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
+ SetEndOfFile(hFile);
+#elif defined(MAC_OSX)
+ // OSX specific version
+ fstore_t fst;
+ fst.fst_flags = F_ALLOCATECONTIG;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = (off_t)offset + length;
+ fst.fst_bytesalloc = 0;
+ if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
+ fst.fst_flags = F_ALLOCATEALL;
+ fcntl(fileno(file), F_PREALLOCATE, &fst);
+ }
+ ftruncate(fileno(file), fst.fst_length);
+#elif defined(__linux__)
+ // Version using posix_fallocate
+ off_t nEndPos = (off_t)offset + length;
+ posix_fallocate(fileno(file), 0, nEndPos);
+#else
+ // Fallback version
+ // TODO: just write one byte per block
static const char buf[65536] = {};
fseek(file, offset, SEEK_SET);
while (length > 0) {
@@ -1164,6 +1210,7 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
length -= now;
}
+#endif
}
void ShrinkDebugFile()
@@ -1218,9 +1265,14 @@ void SetMockTime(int64 nMockTimeIn)
static int64 nTimeOffset = 0;
+int64 GetTimeOffset()
+{
+ return nTimeOffset;
+}
+
int64 GetAdjustedTime()
{
- return GetTime() + nTimeOffset;
+ return GetTime() + GetTimeOffset();
}
void AddTimeData(const CNetAddr& ip, int64 nTime)
@@ -1276,12 +1328,26 @@ void AddTimeData(const CNetAddr& ip, int64 nTime)
}
}
-
-
-
-
-
-
+uint32_t insecure_rand_Rz = 11;
+uint32_t insecure_rand_Rw = 11;
+void seed_insecure_rand(bool fDeterministic)
+{
+ //The seed values have some unlikely fixed points which we avoid.
+ if(fDeterministic)
+ {
+ insecure_rand_Rz = insecure_rand_Rw = 11;
+ } else {
+ uint32_t tmp;
+ do{
+ RAND_bytes((unsigned char*)&tmp,4);
+ }while(tmp==0 || tmp==0x9068ffffU);
+ insecure_rand_Rz=tmp;
+ do{
+ RAND_bytes((unsigned char*)&tmp,4);
+ }while(tmp==0 || tmp==0x464fffffU);
+ insecure_rand_Rw=tmp;
+ }
+}
string FormatVersion(int nVersion)
{
diff --git a/src/util.h b/src/util.h
index 97911d7493..d129d13692 100644
--- a/src/util.h
+++ b/src/util.h
@@ -193,6 +193,7 @@ bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
void FileCommit(FILE *fileout);
int GetFilesize(FILE* file);
+bool TruncateFile(FILE *file, unsigned int length);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest);
boost::filesystem::path GetDefaultDataDir();
@@ -212,6 +213,7 @@ uint256 GetRandHash();
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
+int64 GetTimeOffset();
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
void AddTimeData(const CNetAddr& ip, int64 nTime);
@@ -403,13 +405,27 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
*/
bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+/**
+ * MWC RNG of George Marsaglia
+ * This is intended to be fast. It has a period of 2^59.3, though the
+ * least significant 16 bits only have a period of about 2^30.1.
+ *
+ * @return random value
+ */
+extern uint32_t insecure_rand_Rz;
+extern uint32_t insecure_rand_Rw;
+static inline uint32_t insecure_rand(void)
+{
+ insecure_rand_Rz=36969*(insecure_rand_Rz&65535)+(insecure_rand_Rz>>16);
+ insecure_rand_Rw=18000*(insecure_rand_Rw&65535)+(insecure_rand_Rw>>16);
+ return (insecure_rand_Rw<<16)+insecure_rand_Rz;
+}
-
-
-
-
-
-
+/**
+ * Seed insecure_rand using the random pool.
+ * @param Deterministic Use a determinstic seed
+ */
+void seed_insecure_rand(bool fDeterministic=false);
/** Median filter over a stream of values.
* Returns the median of the last N numbers
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 8b2f03212a..eecb7d2d22 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -8,6 +8,7 @@
#include "crypter.h"
#include "ui_interface.h"
#include "base58.h"
+#include <boost/algorithm/string/replace.hpp>
using namespace std;
@@ -476,6 +477,16 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+
+ // notify an external script when a wallet transaction comes in or is updated
+ std::string strCmd = GetArg("-walletnotify", "");
+
+ if ( !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
}
return true;
}
@@ -973,6 +984,8 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
+ seed_insecure_rand();
+
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
@@ -982,7 +995,13 @@ static void ApproximateBestSubset(vector<pair<int64, pair<const CWalletTx*,unsig
{
for (unsigned int i = 0; i < vValue.size(); i++)
{
- if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
+ //The solver here uses a randomized algorithm,
+ //the randomness serves no real security purpose but is just
+ //needed to prevent degenerate behavior and it is important
+ //that the rng fast. We do not use a constant random sequence,
+ //because there may be some privacy improvement by making
+ //the selection random.
+ if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;
@@ -1190,7 +1209,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
scriptChange.SetDestination(vchPubKey.GetID());
// Insert change txn at random position:
- vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
+ vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1);
wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
}
else
@@ -1208,7 +1227,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
// Limit size
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
- if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
+ if (nBytes >= MAX_STANDARD_TX_SIZE)
return false;
dPriority /= nBytes;
@@ -1278,7 +1297,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
mapRequestCount[wtxNew.GetHash()] = 0;
// Broadcast
- if (!wtxNew.AcceptToMemoryPool())
+ if (!wtxNew.AcceptToMemoryPool(true, false))
{
// This must not fail. The transaction has already been signed and recorded.
printf("CommitTransaction() : Error: Transaction not valid");
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index 2282bed18a..fe9bce21e8 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -203,7 +203,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> hash;
CWalletTx& wtx = pwallet->mapWallet[hash];
ssValue >> wtx;
- if (wtx.CheckTransaction() && (wtx.GetHash() == hash))
+ CValidationState state;
+ if (wtx.CheckTransaction(state) && (wtx.GetHash() == hash) && state.IsValid())
wtx.BindWallet(pwallet);
else
{