aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------README1
-rw-r--r--README.md110
-rw-r--r--bitcoin-qt.pro2
-rw-r--r--contrib/macdeploy/notes.txt2
-rw-r--r--contrib/seeds/README9
-rwxr-xr-xcontrib/seeds/makeseeds.py32
-rwxr-xr-xcontrib/verifysfbinaries/verify.sh4
-rw-r--r--doc/files.txt19
-rw-r--r--src/checkpoints.cpp1
-rw-r--r--src/init.cpp7
-rw-r--r--src/leveldb.cpp16
-rw-r--r--src/leveldb.h23
-rw-r--r--src/main.cpp402
-rw-r--r--src/main.h92
-rw-r--r--src/makefile.unix2
-rw-r--r--src/qt/aboutdialog.cpp8
-rw-r--r--src/qt/aboutdialog.h1
-rw-r--r--src/qt/bitcoinstrings.cpp14
-rw-r--r--src/qt/clientmodel.cpp5
-rw-r--r--src/qt/forms/aboutdialog.ui5
-rw-r--r--src/qt/locale/bitcoin_en.ts171
-rw-r--r--src/rpcmining.cpp5
-rw-r--r--src/rpcrawtransaction.cpp5
-rw-r--r--src/test/miner_tests.cpp4
-rw-r--r--src/test/transaction_tests.cpp12
-rw-r--r--src/wallet.cpp2
-rw-r--r--src/walletdb.cpp3
27 files changed, 588 insertions, 369 deletions
diff --git a/README b/README
deleted file mode 120000
index 42061c01a1..0000000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-README.md \ No newline at end of file
diff --git a/README.md b/README.md
index 1ecb8c7efe..58dc2969a6 100644
--- a/README.md
+++ b/README.md
@@ -1,66 +1,82 @@
-
Bitcoin integration/staging tree
+================================
+
+http://www.bitcoin.org
+
+Copyright (c) 2009-2012 Bitcoin Developers
+
+What is Bitcoin?
+----------------
+
+Bitcoin is an experimental new digital currency that enables instant payments to
+anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
+with no central authority: managing transactions and issuing money are carried
+out collectively by the network. Bitcoin is also the name of the open source
+software which enables the use of this currency.
+
+For more information, as well as an immediately useable, binary version of
+the Bitcoin client sofware, see http://www.bitcoin.org.
+
+License
+-------
+
+Bitcoin is released under the terms of the MIT license. See `COPYING` for more
+information or see http://opensource.org/licenses/MIT.
Development process
-===================
+-------------------
-Developers work in their own trees, then submit pull requests when
-they think their feature or bug fix is ready.
+Developers work in their own trees, then submit pull requests when they think
+their feature or bug fix is ready.
-If it is a simple/trivial/non-controversial change, then one of the
-bitcoin development team members simply pulls it.
+If it is a simple/trivial/non-controversial change, then one of the Bitcoin
+development team members simply pulls it.
-If it is a more complicated or potentially controversial
-change, then the patch submitter will be asked to start a
-discussion (if they haven't already) on the mailing list:
-http://sourceforge.net/mailarchive/forum.php?forum_name=bitcoin-development
+If it is a *more complicated or potentially controversial* change, then the patch
+submitter will be asked to start a discussion (if they haven't already) on the
+[mailing list](http://sourceforge.net/mailarchive/forum.php?forum_name=bitcoin-development).
-The patch will be accepted if there is broad consensus that it is a
-good thing. Developers should expect to rework and resubmit patches
-if they don't match the project's coding conventions (see coding.txt)
-or are controversial.
+The patch will be accepted if there is broad consensus that it is a good thing.
+Developers should expect to rework and resubmit patches if the code doesn't
+match the project's coding conventions (see `doc/coding.txt`) or are
+controversial.
-The master branch is regularly built and tested, but is not guaranteed
-to be completely stable. Tags are regularly created to indicate new
-official, stable release versions of Bitcoin.
+The `master` branch is regularly built and tested, but is not guaranteed to be
+completely stable. [Tags](https://github.com/bitcoin/bitcoin/tags) are created
+regularly to indicate new official, stable release versions of Bitcoin.
Testing
-=======
+-------
+
+Testing and code review is the bottleneck for development; we get more pull
+requests than we can review and test. Please be patient and help out, and
+remember this is a security-critical project where any mistake might cost people
+lots of money.
+
+### Automated Testing
-Testing and code review is the bottleneck for development; we get more
-pull requests than we can review and test. Please be patient and help
-out, and remember this is a security-critical project where any
-mistake might cost people lots of money.
+Developers are strongly encouraged to write unit tests for new code, and to
+submit new unit tests for old code.
-Automated Testing
------------------
+Unit tests for the core code are in `src/test/`. To compile and run them:
-Developers are strongly encouraged to write unit tests for new code,
-and to submit new unit tests for old code.
+ cd src; make -f makefile.linux test
-Unit tests for the core code are in src/test/
-To compile and run them:
- cd src; make -f makefile.linux test
+Unit tests for the GUI code are in `src/qt/test/`. To compile and run them:
-Unit tests for the GUI code are in src/qt/test/
-To compile and run them:
- qmake BITCOIN_QT_TEST=1 -o Makefile.test bitcoin-qt.pro
- make -f Makefile.test
- ./Bitcoin-Qt
+ qmake BITCOIN_QT_TEST=1 -o Makefile.test bitcoin-qt.pro
+ make -f Makefile.test
+ ./Bitcoin-Qt
-Every pull request is built for both Windows and
-Linux on a dedicated server, and unit and sanity
-tests are automatically run. The binaries
-produced may be used for manual QA testing
-(a link to them will appear in a comment on the pull request
-from 'BitcoinPullTester').
-See https://github.com/TheBlueMatt/test-scripts for the
-build/test scripts.
+Every pull request is built for both Windows and Linux on a dedicated server,
+and unit and sanity tests are automatically run. The binaries produced may be
+used for manual QA testing -- a link to them will appear in a comment on the
+pull request posted by 'BitcoinPullTester'. See `https://github.com/TheBlueMatt/test-scripts`
+for the build/test scripts.
-Manual Quality Assurance (QA) Testing
--------------------------------------
+### Manual Quality Assurance (QA) Testing
-Large changes should have a test plan, and should be tested
-by somebody other than the developer who wrote the code.
+Large changes should have a test plan, and should be tested by somebody other
+than the developer who wrote the code.
-See https://github.com/bitcoin/QA/ for how to create a test plan.
+See `https://github.com/bitcoin/QA/` for how to create a test plan.
diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro
index 6c1c4a78cc..8a6f9efebd 100644
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -372,6 +372,8 @@ win32:!contains(MINGW_THREAD_BUGFIX, 0) {
!win32:!macx {
DEFINES += LINUX
LIBS += -lrt
+ # _FILE_OFFSET_BITS=64 lets 32-bit fopen transparently support large files.
+ DEFINES += _FILE_OFFSET_BITS=64
}
macx:HEADERS += src/qt/macdockiconhandler.h
diff --git a/contrib/macdeploy/notes.txt b/contrib/macdeploy/notes.txt
index a3f0b5447d..3d74901437 100644
--- a/contrib/macdeploy/notes.txt
+++ b/contrib/macdeploy/notes.txt
@@ -5,7 +5,7 @@ Python 2.7 and make it your default Python installation.
You will need the appscript package for the fancy disk image creation to work.
Install it by invoking "sudo easy_install appscript".
-Ths script should be invoked in the target directory like this:
+This script should be invoked in the target directory like this:
$source_dir/contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr da,de,es,hu,ru,uk,zh_CN,zh_TW -dmg -fancy $source_dir/contrib/macdeploy/fancy.plist -verbose 2
During the process, the disk image window will pop up briefly where the fancy
diff --git a/contrib/seeds/README b/contrib/seeds/README
new file mode 100644
index 0000000000..97e3e1ec71
--- /dev/null
+++ b/contrib/seeds/README
@@ -0,0 +1,9 @@
+Utility to generate the pnSeed[] array that is compiled into the client
+(see src/net.cpp).
+
+The 600 seeds compiled into the 0.8 release were created from sipa's DNS seed data, like this:
+
+curl -s http://bitcoin.sipa.be/seeds.txt | head -1000 | makeseeds.py
+
+The input to makeseeds.py is assumed to be approximately sorted from most-reliable to least-reliable,
+with IP:port first on each line (lines that don't match IPv4:port are ignored).
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
new file mode 100755
index 0000000000..1d01fd7d20
--- /dev/null
+++ b/contrib/seeds/makeseeds.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+#
+# Generate pnSeed[] from Pieter's DNS seeder
+#
+
+NSEEDS=600
+
+import re
+import sys
+from subprocess import check_output
+
+def main():
+ lines = sys.stdin.readlines()
+
+ ips = []
+ pattern = re.compile(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}):8333")
+ for line in lines:
+ m = pattern.match(line)
+ if m is None:
+ continue
+ ip = 0
+ for i in range(0,4):
+ ip = ip + (int(m.group(i+1)) << (8*(i)))
+ if ip == 0:
+ continue
+ ips.append(ip)
+
+ for row in range(0, min(NSEEDS,len(ips)), 8):
+ print " " + ", ".join([ "0x%08x"%i for i in ips[row:row+8] ]) + ","
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/verifysfbinaries/verify.sh b/contrib/verifysfbinaries/verify.sh
index 336de3ec1f..149b7b394c 100755
--- a/contrib/verifysfbinaries/verify.sh
+++ b/contrib/verifysfbinaries/verify.sh
@@ -18,7 +18,7 @@ WORKINGDIR="/tmp/bitcoin"
TMPFILE="hashes.tmp"
#this URL is used if a version number is not specified as an argument to the script
-SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.7.1/test/SHA256SUMS.asc"
+SIGNATUREFILE="http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.7.2/SHA256SUMS.asc"
SIGNATUREFILENAME="SHA256SUMS.asc"
RCSUBDIR="test/"
@@ -81,7 +81,7 @@ if [ $RET -ne 0 ]; then
#and notify the user if it's bad
echo "Bad signature."
elif [ $RET -eq 2 ]; then
- #or if a gpg error has occured
+ #or if a gpg error has occurred
echo "gpg error. Do you have Gavin's code signing key installed?"
fi
diff --git a/doc/files.txt b/doc/files.txt
new file mode 100644
index 0000000000..5d4cdabf8d
--- /dev/null
+++ b/doc/files.txt
@@ -0,0 +1,19 @@
+Used in 0.8.0:
+* wallet.dat: personal wallet (BDB) with keys and transactions
+* peers.dat: peer IP address database (custom format); since 0.7.0
+* blocks/blk000??.dat: block data (custom, 128 MiB per file); since 0.8.0
+* blocks/rev000??.dat; block undo data (custom); since 0.8.0 (format changed since pre-0.8)
+* blocks/index/*; block index (LevelDB); since 0.8.0
+* chainstate/*; block chain state database (LevelDB); since 0.8.0
+* database/*: BDB database environment; only used for wallet since 0.8.0
+
+Only used in pre-0.8.0:
+* blktree/*; block chain index (LevelDB); since pre-0.8, replaced by blocks/index/* in 0.8.0
+* coins/*; unspent transaction output database (LevelDB); since pre-0.8, replaced by chainstate/* in 0.8.0
+
+Only used before 0.8.0:
+* blkindex.dat: block chain index database (BDB); replaced by {chainstate/*,blocks/index/*,blocks/rev000??.dat} in 0.8.0
+* blk000?.dat: block data (custom, 2 GiB per file); replaced by blocks/blk000??.dat in 0.8.0
+
+Only used before 0.7.0:
+* addr.dat: peer IP address database (BDB); replaced by peers.dat in 0.7.0
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 4d2096ef07..e2c420edd7 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -31,6 +31,7 @@ namespace Checkpoints
(168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
(193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
(210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
+ (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"))
;
static MapCheckpoints mapCheckpointsTestnet =
diff --git a/src/init.cpp b/src/init.cpp
index 9b9415a8ed..2f37dad56c 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -187,9 +187,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);
@@ -936,7 +936,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 fe35fbaf29..847b1ea8a6 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)
{
@@ -524,28 +515,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
@@ -553,20 +544,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;
@@ -633,18 +624,18 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
}
-bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
+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())
@@ -717,7 +708,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
// 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();
@@ -769,7 +760,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
// 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());
}
@@ -798,9 +789,13 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
return true;
}
-bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs)
+bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs)
{
- return mempool.accept(*this, fCheckInputs, fLimitFree, 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)
@@ -913,7 +908,8 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs, bool fLimitFree)
{
- return CTransaction::AcceptToMemoryPool(fCheckInputs, fLimitFree);
+ CValidationState state;
+ return CTransaction::AcceptToMemoryPool(state, fCheckInputs, fLimitFree);
}
@@ -1209,11 +1205,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;
@@ -1252,8 +1250,13 @@ bool ConnectBestBlock() {
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
if (fRequestShutdown)
break;
- if (!SetBestChain(pindexSwitch))
- return false;
+ CValidationState state;
+ try {
+ if (!SetBestChain(state, pindexSwitch))
+ return false;
+ } catch(std::runtime_error &e) {
+ return state.Abort(_("System error: ") + e.what());
+ }
}
return true;
}
@@ -1315,22 +1318,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;
}
@@ -1368,7 +1369,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())
{
@@ -1378,7 +1379,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.
@@ -1393,26 +1394,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("ChecktInputs() : %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.
@@ -1432,7 +1433,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);
}
}
}
@@ -1441,56 +1442,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());
@@ -1591,7 +1545,7 @@ void static FlushBlockFile()
}
}
-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);
@@ -1606,10 +1560,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
@@ -1674,12 +1628,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)
{
@@ -1688,19 +1642,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);
@@ -1713,10 +1667,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));
@@ -1729,10 +1683,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;
@@ -1743,15 +1697,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++)
@@ -1760,7 +1714,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.
@@ -1771,13 +1725,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)
@@ -1801,9 +1756,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);
@@ -1821,11 +1776,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)
@@ -1839,8 +1796,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);
@@ -1848,10 +1804,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.
@@ -1868,8 +1831,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(true, false);
+ 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) {
@@ -1926,17 +1892,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);
@@ -1954,10 +1919,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)
@@ -1968,14 +1934,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;
@@ -2017,19 +1984,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;
@@ -2040,15 +2007,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;
@@ -2063,41 +2030,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
@@ -2111,7 +2078,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)
@@ -2119,21 +2086,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;
@@ -2141,26 +2108,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)
@@ -2168,7 +2135,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
@@ -2180,23 +2147,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();
@@ -2223,17 +2194,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);
@@ -2243,9 +2214,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);
@@ -2253,9 +2222,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"));
}
}
@@ -2278,7 +2245,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
@@ -2292,7 +2259,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
++mi)
{
CBlock* pblockOrphan = (*mi).second;
- if (pblockOrphan->AcceptBlock())
+ if (pblockOrphan->AcceptBlock(state))
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
@@ -2464,6 +2431,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)
{
@@ -2471,15 +2446,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;
}
@@ -2621,6 +2589,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)
@@ -2630,7 +2599,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) {
@@ -2644,7 +2613,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) {
@@ -2665,7 +2634,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());
}
}
@@ -2746,11 +2715,12 @@ bool LoadBlockIndex()
// Start new block file
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos;
- if (!FindBlockPos(blockPos, nBlockSize+8, 0, block.nTime))
+ 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(blockPos))
+ if (!block.AddToBlockIndex(state, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
}
@@ -2834,7 +2804,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) {
@@ -2880,14 +2850,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);
@@ -3457,7 +3432,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
- if (tx.AcceptToMemoryPool(true, true, &fMissingInputs))
+ CValidationState state;
+ if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs))
{
RelayTransaction(tx, inv.hash, vMsg);
mapAlreadyAskedFor.erase(inv);
@@ -3478,7 +3454,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_TX, tx.GetHash());
bool fMissingInputs2 = false;
- if (tx.AcceptToMemoryPool(true, true, &fMissingInputs2))
+ if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
RelayTransaction(tx, inv.hash, vMsg);
@@ -3507,7 +3483,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);
}
@@ -3522,9 +3500,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);
}
@@ -4274,12 +4255,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
@@ -4337,7 +4319,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");
}
@@ -4439,7 +4422,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 9dbcac0b5a..23a4d3ba31 100644
--- a/src/main.h
+++ b/src/main.h
@@ -106,15 +106,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 +124,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) */
@@ -172,13 +174,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 +458,6 @@ public:
-
enum GetMinFee_mode
{
GMF_BLOCK,
@@ -474,10 +477,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 +497,6 @@ public:
vin.clear();
vout.clear();
nLockTime = 0;
- nDoS = 0; // Denial-of-service prevention
}
bool IsNull() const
@@ -654,27 +652,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 fLimitFree = 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);
@@ -1320,10 +1315,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();
@@ -1346,7 +1337,6 @@ public:
CBlockHeader::SetNull();
vtx.clear();
vMerkleTree.clear();
- nDoS = 0;
}
CBlockHeader GetBlockHeader() const
@@ -1494,23 +1484,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);
};
@@ -1877,6 +1867,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;
+ }
+};
@@ -2025,7 +2061,7 @@ public:
std::map<uint256, CTransaction> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
- bool accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree, 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.unix b/src/makefile.unix
index 14cf1b8fa5..b52a0f8aea 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))
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/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 92a511adb9..5bd1517091 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -109,13 +109,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 +174,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..084ad12a56 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -48,7 +48,10 @@ 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
}
void ClientModel::updateTimer()
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/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 4895e9ba4e..18249b1669 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="+95"/>
<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="-26"/>
<source>Don&apos;t generate coins</source>
<translation>Don&apos;t generate coins</translation>
</message>
<message>
- <location line="+62"/>
+ <location line="+73"/>
<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="-46"/>
<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="+77"/>
<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="-129"/>
<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="+74"/>
<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="-105"/>
<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>
@@ -2425,16 +2430,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 +2609,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 +2654,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="-65"/>
<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="+74"/>
<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="-117"/>
<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="+139"/>
<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 +2689,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 +2704,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="-147"/>
<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="+159"/>
<source>This help message</source>
<translation>This help message</translation>
</message>
@@ -2654,7 +2719,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="-83"/>
<source>Connect through socks proxy</source>
<translation>Connect through socks proxy</translation>
</message>
@@ -2664,12 +2729,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="+54"/>
<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 +2744,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 +2759,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 +2779,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="-88"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -2724,17 +2789,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="+42"/>
<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 +2814,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="-56"/>
<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 +2824,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="+65"/>
<source>Find peers using internet relay chat (default: 0)</source>
<translation>Find peers using internet relay chat (default: 0)</translation>
</message>
@@ -2774,7 +2839,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="-51"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
@@ -2789,22 +2854,22 @@ 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="+61"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-44"/>
+ <location line="-55"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+66"/>
+ <location line="+78"/>
<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>
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 778e0acbd2..b9ebcb4001 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -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/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 8d89c2f302..5224051ace 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -546,8 +546,9 @@ Value sendrawtransaction(const Array& params, bool fHelp)
fHave = view.GetCoins(hashTx, existingCoins);
if (!fHave) {
// push to local node
- if (!tx.AcceptToMemoryPool(true, false))
- 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/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/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/wallet.cpp b/src/wallet.cpp
index 557784e5c2..b8ef2a20bf 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1190,7 +1190,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
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
{