aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus10
-rw-r--r--depends/packages/native_comparisontool.mk6
-rw-r--r--src/core.cpp53
-rw-r--r--src/core.h6
-rw-r--r--src/init.cpp9
-rw-r--r--src/main.cpp21
6 files changed, 74 insertions, 31 deletions
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index 1b50981f0a..8f826ace09 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -292,7 +292,7 @@ def copyFramework(framework, path, verbose):
fromResourcesDir = framework.sourceResourcesDirectory
if os.path.exists(fromResourcesDir):
toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory)
- shutil.copytree(fromResourcesDir, toResourcesDir)
+ shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True)
if verbose >= 3:
print "Copied resources:", fromResourcesDir
print " to:", toResourcesDir
@@ -301,7 +301,7 @@ def copyFramework(framework, path, verbose):
fromContentsDir = framework.sourceContentsDirectory
if os.path.exists(fromContentsDir):
toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory)
- shutil.copytree(fromContentsDir, toContentsDir)
+ shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
contentslinkfrom = os.path.join(path, framework.destinationContentsDirectory)
if verbose >= 3:
print "Copied Contents:", fromContentsDir
@@ -310,7 +310,7 @@ def copyFramework(framework, path, verbose):
qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib")
qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib")
if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath):
- shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath)
+ shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True)
if verbose >= 3:
print "Copied for libQtGui:", qtMenuNibSourcePath
print " to:", qtMenuNibDestinationPath
@@ -584,7 +584,7 @@ if verbose >= 3:
print app_bundle, "->", target
os.mkdir("dist")
-shutil.copytree(app_bundle, target)
+shutil.copytree(app_bundle, target, symlinks=True)
applicationBundle = ApplicationBundleInfo(target)
@@ -671,7 +671,7 @@ for p in config.add_resources:
if verbose >= 3:
print p, "->", t
if os.path.isdir(p):
- shutil.copytree(p, t)
+ shutil.copytree(p, t, symlinks=True)
else:
shutil.copy2(p, t)
diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk
index d9f7722190..4c40f8b123 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/src/core.cpp b/src/core.cpp
index 1489d77bb3..380b1c38e0 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 e8435c8b0d..a348293578 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 503df7ad3f..980c589b29 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 5a5c700574..a3e36ff872 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);