aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--depends/packages/native_comparisontool.mk6
-rw-r--r--doc/release-process.md4
-rwxr-xr-xqa/pull-tester/run-bitcoind-for-test.sh.in4
-rw-r--r--src/amount.h4
-rw-r--r--src/chainparams.cpp41
-rw-r--r--src/chainparams.h24
-rw-r--r--src/chainparamsbase.cpp17
-rw-r--r--src/chainparamsbase.h1
-rw-r--r--src/checkpoints.cpp2
-rw-r--r--src/core.cpp53
-rw-r--r--src/core.h6
-rw-r--r--src/init.cpp9
-rw-r--r--src/main.cpp24
-rw-r--r--src/pow.cpp4
-rw-r--r--src/test/base58_tests.cpp4
-rw-r--r--src/test/miner_tests.cpp1
-rw-r--r--src/test/test_bitcoin.cpp2
-rw-r--r--src/util.h1
18 files changed, 174 insertions, 33 deletions
diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk
index d9f772219..4c40f8b12 100644
--- a/depends/packages/native_comparisontool.mk
+++ b/depends/packages/native_comparisontool.mk
@@ -1,8 +1,8 @@
package=native_comparisontool
-$(package)_version=adfd3de7
-$(package)_download_path=https://github.com/TheBlueMatt/test-scripts/raw/10222bfdace65a0c5f3bd4a766eeb6b3a8b869fb/
+$(package)_version=5caed78
+$(package)_download_path=https://github.com/TheBlueMatt/test-scripts/raw/2d76ce92d68e6746988adde731318605a70e252c
$(package)_file_name=pull-tests-$($(package)_version).jar
-$(package)_sha256_hash=fd2282b112e35f339dbe3729b08a04834ad719f8c9c10eeec1178465e6d36a18
+$(package)_sha256_hash=b55a98828b17060e327c5dabe5e4631898f422c0cba07c46170930a9eaf5e7c0
$(package)_install_dirname=BitcoindComparisonTool_jar
$(package)_install_filename=BitcoindComparisonTool.jar
diff --git a/doc/release-process.md b/doc/release-process.md
index 940f934ba..7699af90b 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -154,6 +154,10 @@ repackage gitian builds for release as stand-alone zip/tar/installer exe
zip -r bitcoin-${VERSION}-win.zip bitcoin-${VERSION}-win
rm -rf bitcoin-${VERSION}-win
+**Mac OS X .dmg:**
+
+ mv Bitcoin-Qt.dmg bitcoin-${VERSION}-osx.dmg
+
###Next steps:
Commit your signature to gitian.sigs:
diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in
index 67318e5a4..210fc3c42 100755
--- a/qa/pull-tester/run-bitcoind-for-test.sh.in
+++ b/qa/pull-tester/run-bitcoind-for-test.sh.in
@@ -29,4 +29,8 @@ fi
kill $BITCOIND && wait $BITCOIND
# timeout returns 124 on timeout, otherwise the return value of the child
+
+# If $RETURN is not 0, the test failed. Dump the tail of the debug log.
+if [ $RETURN -ne 0 ]; then tail -n 200 $DATADIR/regtest/debug.log; fi
+
exit $RETURN
diff --git a/src/amount.h b/src/amount.h
index 42006a038..831fa1f6c 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_AMOUNT_H
@@ -10,4 +10,4 @@
typedef int64_t CAmount;
-#endif
+#endif // BITCOIN_AMOUNT_H
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 179db5a81..31c67715c 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -115,6 +115,7 @@ public:
fAllowMinDifficultyBlocks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
+ fSkipProofOfWorkCheck = false;
}
};
static CMainParams mainParams;
@@ -214,8 +215,46 @@ public:
};
static CRegTestParams regTestParams;
+//
+// Unit test
+//
+class CUnitTestParams : public CMainParams, public CModifiableParams {
+public:
+ CUnitTestParams() {
+ networkID = CBaseChainParams::UNITTEST;
+ strNetworkID = "unittest";
+ nDefaultPort = 18445;
+ vFixedSeeds.clear();
+ vSeeds.clear(); // Regtest mode doesn't have any DNS seeds.
+
+ fRequireRPCPassword = false;
+ fMiningRequiresPeers = false;
+ fDefaultCheckMemPool = true;
+ fAllowMinDifficultyBlocks = false;
+ fMineBlocksOnDemand = true;
+ }
+public:
+ // Published setters to allow changing values in unit test cases
+ virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval=anSubsidyHalvingInterval; }
+ virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority=anEnforceBlockUpgradeMajority; }
+ virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) { nRejectBlockOutdatedMajority=anRejectBlockOutdatedMajority; }
+ virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) { nToCheckBlockUpgradeMajority=anToCheckBlockUpgradeMajority; }
+ virtual void setDefaultCheckMemPool(bool afDefaultCheckMemPool) { fDefaultCheckMemPool=afDefaultCheckMemPool; }
+ virtual void setAllowMinDifficultyBlocks(bool afAllowMinDifficultyBlocks) { fAllowMinDifficultyBlocks=afAllowMinDifficultyBlocks; }
+ virtual void setSkipProofOfWorkCheck(bool afSkipProofOfWorkCheck) { fSkipProofOfWorkCheck = afSkipProofOfWorkCheck; }
+};
+static CUnitTestParams unitTestParams;
+
+
static CChainParams *pCurrentParams = 0;
+CModifiableParams *ModifiableParams()
+{
+ assert(pCurrentParams);
+ assert(pCurrentParams==&unitTestParams);
+ return (CModifiableParams*)&unitTestParams;
+}
+
const CChainParams &Params() {
assert(pCurrentParams);
return *pCurrentParams;
@@ -229,6 +268,8 @@ CChainParams &Params(CBaseChainParams::Network network) {
return testNetParams;
case CBaseChainParams::REGTEST:
return regTestParams;
+ case CBaseChainParams::UNITTEST:
+ return unitTestParams;
default:
assert(false && "Unimplemented network");
return mainParams;
diff --git a/src/chainparams.h b/src/chainparams.h
index e5dfc87c6..50441a89f 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -61,6 +61,8 @@ public:
bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; }
/* Allow mining of a min-difficulty block */
bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; }
+ /* Skip proof-of-work check: allow mining of any difficulty block */
+ bool SkipProofOfWorkCheck() const { return fSkipProofOfWorkCheck; }
/* Make standard checks */
bool RequireStandard() const { return fRequireStandard; }
int64_t TargetTimespan() const { return nTargetTimespan; }
@@ -103,8 +105,27 @@ protected:
bool fAllowMinDifficultyBlocks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
+ bool fSkipProofOfWorkCheck;
};
+/** Modifiable parameters interface is used by test cases to adapt the parameters in order
+*** to test specific features more easily. Test cases should always restore the previous
+*** values after finalization.
+**/
+
+class CModifiableParams {
+public:
+ // Published setters to allow changing values in unit test cases
+ virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) =0;
+ virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority)=0;
+ virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority)=0;
+ virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority)=0;
+ virtual void setDefaultCheckMemPool(bool aDefaultCheckMemPool)=0;
+ virtual void setAllowMinDifficultyBlocks(bool aAllowMinDifficultyBlocks)=0;
+ virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck)=0;
+};
+
+
/**
* Return the currently selected parameters. This won't change after app startup
* outside of the unit tests.
@@ -114,6 +135,9 @@ const CChainParams &Params();
/** Return parameters for the given network. */
CChainParams &Params(CBaseChainParams::Network network);
+/** Get modifyable network parameters (UNITTEST only) */
+CModifiableParams *ModifiableParams();
+
/** Sets the params returned by Params() to those for the given network. */
void SelectParams(CBaseChainParams::Network network);
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 98bb5b855..e9d63197b 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -57,6 +57,20 @@ public:
};
static CBaseRegTestParams regTestParams;
+//
+// Unit test
+//
+class CBaseUnitTestParams : public CBaseMainParams
+{
+public:
+ CBaseUnitTestParams()
+ {
+ networkID = CBaseChainParams::UNITTEST;
+ strDataDir = "unittest";
+ }
+};
+static CBaseUnitTestParams unitTestParams;
+
static CBaseChainParams* pCurrentBaseParams = 0;
const CBaseChainParams& BaseParams()
@@ -77,6 +91,9 @@ void SelectBaseParams(CBaseChainParams::Network network)
case CBaseChainParams::REGTEST:
pCurrentBaseParams = &regTestParams;
break;
+ case CBaseChainParams::UNITTEST:
+ pCurrentBaseParams = &unitTestParams;
+ break;
default:
assert(false && "Unimplemented network");
return;
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index c054f03f1..cc154cf50 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -19,6 +19,7 @@ public:
MAIN,
TESTNET,
REGTEST,
+ UNITTEST,
MAX_NETWORK_TYPES
};
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index c41deea7c..9a6bc05e6 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -88,6 +88,8 @@ namespace Checkpoints {
return dataTestnet;
else if (Params().NetworkID() == CBaseChainParams::MAIN)
return data;
+ else if (Params().NetworkID() == CBaseChainParams::UNITTEST) // UnitTest share the same checkpoints as MAIN
+ return data;
else
return dataRegtest;
}
diff --git a/src/core.cpp b/src/core.cpp
index 1489d77bb..380b1c38e 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -224,29 +224,66 @@ uint256 CBlockHeader::GetHash() const
return Hash(BEGIN(nVersion), END(nNonce));
}
-uint256 CBlock::BuildMerkleTree() const
+uint256 CBlock::BuildMerkleTree(bool* fMutated) const
{
- // WARNING! If you're reading this because you're learning about crypto
- // and/or designing a new system that will use merkle trees, keep in mind
- // that the following merkle tree algorithm has a serious flaw related to
- // duplicate txids, resulting in a vulnerability. (CVE-2012-2459) Bitcoin
- // has since worked around the flaw, but for new applications you should
- // use something different; don't just copy-and-paste this code without
- // understanding the problem first.
+ /* WARNING! If you're reading this because you're learning about crypto
+ and/or designing a new system that will use merkle trees, keep in mind
+ that the following merkle tree algorithm has a serious flaw related to
+ duplicate txids, resulting in a vulnerability (CVE-2012-2459).
+
+ The reason is that if the number of hashes in the list at a given time
+ is odd, the last one is duplicated before computing the next level (which
+ is unusual in Merkle trees). This results in certain sequences of
+ transactions leading to the same merkle root. For example, these two
+ trees:
+
+ A A
+ / \ / \
+ B C B C
+ / \ | / \ / \
+ D E F D E F F
+ / \ / \ / \ / \ / \ / \ / \
+ 1 2 3 4 5 6 1 2 3 4 5 6 5 6
+
+ for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and
+ 6 are repeated) result in the same root hash A (because the hash of both
+ of (F) and (F,F) is C).
+
+ The vulnerability results from being able to send a block with such a
+ transaction list, with the same merkle root, and the same block hash as
+ the original without duplication, resulting in failed validation. If the
+ receiving node proceeds to mark that block as permanently invalid
+ however, it will fail to accept further unmodified (and thus potentially
+ valid) versions of the same block. We defend against this by detecting
+ the case where we would hash two identical hashes at the end of the list
+ together, and treating that identically to the block having an invalid
+ merkle root. Assuming no double-SHA256 collisions, this will detect all
+ known ways of changing the transactions without affecting the merkle
+ root.
+ */
vMerkleTree.clear();
+ vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
BOOST_FOREACH(const CTransaction& tx, vtx)
vMerkleTree.push_back(tx.GetHash());
int j = 0;
+ bool mutated = false;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
for (int i = 0; i < nSize; i += 2)
{
int i2 = std::min(i+1, nSize-1);
+ if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) {
+ // Two identical hashes at the end of the list at a particular level.
+ mutated = true;
+ }
vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
}
j += nSize;
}
+ if (fMutated) {
+ *fMutated = mutated;
+ }
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}
diff --git a/src/core.h b/src/core.h
index e8435c8b0..a34829357 100644
--- a/src/core.h
+++ b/src/core.h
@@ -529,7 +529,11 @@ public:
return block;
}
- uint256 BuildMerkleTree() const;
+ // Build the in-memory merkle tree for this block and return the merkle root.
+ // If non-NULL, *mutated is set to whether mutation was detected in the merkle
+ // tree (a duplication of transactions in the block leading to an identical
+ // merkle root).
+ uint256 BuildMerkleTree(bool* mutated = NULL) const;
std::vector<uint256> GetMerkleBranch(int nIndex) const;
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
diff --git a/src/init.cpp b/src/init.cpp
index 503df7ad3..980c589b2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -45,7 +45,7 @@ using namespace boost;
using namespace std;
#ifdef ENABLE_WALLET
-CWallet* pwalletMain;
+CWallet* pwalletMain = NULL;
#endif
#ifdef WIN32
@@ -109,7 +109,7 @@ bool ShutdownRequested()
return fRequestShutdown;
}
-static CCoinsViewDB *pcoinsdbview;
+static CCoinsViewDB *pcoinsdbview = NULL;
void Shutdown()
{
@@ -165,8 +165,8 @@ void Shutdown()
#endif
UnregisterAllWallets();
#ifdef ENABLE_WALLET
- if (pwalletMain)
- delete pwalletMain;
+ delete pwalletMain;
+ pwalletMain = NULL;
#endif
LogPrintf("%s: done\n", __func__);
}
@@ -701,6 +701,7 @@ bool AppInit2(boost::thread_group& threadGroup)
fIsBareMultisigStd = GetArg("-permitbaremultisig", true) != 0;
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
+
// Sanity check
if (!InitSanityCheck())
return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down."));
diff --git a/src/main.cpp b/src/main.cpp
index 5a5c70057..55485c86f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,6 +17,7 @@
#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilmoneystr.h"
#include <sstream>
@@ -1316,7 +1317,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CScriptCheck::operator()() const {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags))
- return error("CScriptCheck() : %s VerifySignature failed", ptxTo->GetHash().ToString());
+ return error("CScriptCheck() : %s:%d VerifySignature failed", ptxTo->GetHash().ToString(), nIn);
return true;
}
@@ -1361,7 +1362,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
}
if (nValueIn < tx.GetValueOut())
- return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString()),
+ return state.DoS(100, error("CheckInputs() : %s value in (%s) < value out (%s)",
+ tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())),
REJECT_INVALID, "bad-txns-in-belowout");
// Tally transaction fees
@@ -2236,13 +2238,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
if (!CheckTransaction(tx, state))
return error("CheckBlock() : CheckTransaction failed");
- // Check for duplicate txids. This is caught by ConnectInputs(),
- // but catching it earlier avoids a potential DoS attack:
- set<uint256> uniqueTx;
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- uniqueTx.insert(tx.GetHash());
- }
- if (uniqueTx.size() != block.vtx.size())
+ // Check for merkle tree malleability (CVE-2012-2459): repeating sequences
+ // of transactions in a block without affecting the merkle root of a block,
+ // while still invalidating it.
+ bool mutated;
+ uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated);
+ if (mutated)
return state.DoS(100, error("CheckBlock() : duplicate transaction"),
REJECT_INVALID, "bad-txns-duplicate", true);
@@ -2256,7 +2257,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
REJECT_INVALID, "bad-blk-sigops", true);
// Check merkle root
- if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
+ if (fCheckMerkleRoot && block.hashMerkleRoot != hashMerkleRoot2)
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"),
REJECT_INVALID, "bad-txnmrklroot", true);
@@ -2304,7 +2305,8 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex
nHeight = pindexPrev->nHeight+1;
// Check proof of work
- if (block.nBits != GetNextWorkRequired(pindexPrev, &block))
+ if ((!Params().SkipProofOfWorkCheck()) &&
+ (block.nBits != GetNextWorkRequired(pindexPrev, &block)))
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"),
REJECT_INVALID, "bad-diffbits");
diff --git a/src/pow.cpp b/src/pow.cpp
index 893f6c18b..d50222849 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -81,6 +81,10 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
bool fNegative;
bool fOverflow;
uint256 bnTarget;
+
+ if (Params().SkipProofOfWorkCheck())
+ return true;
+
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
// Check range
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 58fffb6df..c298c805d 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest);
}
}
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::UNITTEST);
}
// Goal: check that generated keys match test vectors
@@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CTxDestination nodest = CNoDestination();
BOOST_CHECK(!dummyAddr.Set(nodest));
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::UNITTEST);
}
// Goal: check that base58 parsing code is robust against a variety of corrupted data
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 9e4669eba..bad5c13ac 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -253,6 +253,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.Tip()->nHeight--;
SetMockTime(0);
+ mempool.clear();
BOOST_FOREACH(CTransaction *tx, txFirst)
delete tx;
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 68fad8d03..6e5f0e3fa 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -31,7 +31,7 @@ struct TestingSetup {
TestingSetup() {
fPrintToDebugLog = false; // don't want to write to debug.log file
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(CBaseChainParams::UNITTEST);
noui_connect();
#ifdef ENABLE_WALLET
bitdb.MakeMock();
diff --git a/src/util.h b/src/util.h
index fb1d3eacb..4b2415278 100644
--- a/src/util.h
+++ b/src/util.h
@@ -14,7 +14,6 @@
#include "config/bitcoin-config.h"
#endif
-#include "amount.h"
#include "compat.h"
#include "tinyformat.h"
#include "utiltime.h"