diff options
-rw-r--r-- | doc/release-process.md | 17 | ||||
-rw-r--r-- | src/Makefile.test.include | 1 | ||||
-rw-r--r-- | src/alert.cpp | 9 | ||||
-rw-r--r-- | src/alert.h | 4 | ||||
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | src/pow.cpp | 6 | ||||
-rw-r--r-- | src/qt/forms/sendcoinsdialog.ui | 2 | ||||
-rw-r--r-- | src/test/alert_tests.cpp | 7 | ||||
-rw-r--r-- | src/test/mempool_tests.cpp | 104 | ||||
-rw-r--r-- | src/txmempool.cpp | 12 |
10 files changed, 153 insertions, 19 deletions
diff --git a/doc/release-process.md b/doc/release-process.md index 016090c594..5dad9bf5de 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -133,15 +133,22 @@ rm SHA256SUMS Note: check that SHA256SUMS itself doesn't end up in SHA256SUMS, which is a spurious/nonsensical entry. - Upload zips and installers, as well as `SHA256SUMS.asc` from last step, to the bitcoin.org server + into `/var/www/bin/bitcoin-core-${VERSION}` - Update bitcoin.org version - - Make a pull request to add a file named `YYYY-MM-DD-vX.Y.Z.md` with the release notes - to https://github.com/bitcoin/bitcoin.org/tree/master/_releases - ([Example for 0.9.2.1](https://raw.githubusercontent.com/bitcoin/bitcoin.org/master/_releases/2014-06-19-v0.9.2.1.md)). + - First, check to see if the Bitcoin.org maintainers have prepared a + release: https://github.com/bitcoin/bitcoin.org/labels/Releases - - After the pull request is merged, the website will automatically show the newest version, as well - as update the OS download links. Ping Saivann in case anything goes wrong + - If they have, it will have previously failed their Travis CI + checks because the final release files weren't uploaded. + Trigger a Travis CI rebuild---if it passes, merge. + + - If they have not prepared a release, follow the Bitcoin.org release + instructions: https://github.com/bitcoin/bitcoin.org#release-notes + + - After the pull request is merged, the website will automatically show the newest version within 15 minutes, as well + as update the OS download links. Ping @saivann/@harding (saivann/harding on Freenode) in case anything goes wrong - Announce the release: diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8dd0a28454..52ff3f224f 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -50,6 +50,7 @@ BITCOIN_TESTS =\ test/hash_tests.cpp \ test/key_tests.cpp \ test/main_tests.cpp \ + test/mempool_tests.cpp \ test/miner_tests.cpp \ test/mruset_tests.cpp \ test/multisig_tests.cpp \ diff --git a/src/alert.cpp b/src/alert.cpp index 323939913b..aa7ac748da 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -5,7 +5,6 @@ #include "alert.h" -#include "chainparams.h" #include "clientversion.h" #include "net.h" #include "pubkey.h" @@ -145,9 +144,9 @@ bool CAlert::RelayTo(CNode* pnode) const return false; } -bool CAlert::CheckSignature() const +bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const { - CPubKey key(Params().AlertKey()); + CPubKey key(alertKey); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CAlert::CheckSignature(): verify signature failed"); @@ -169,9 +168,9 @@ CAlert CAlert::getAlertByHash(const uint256 &hash) return retval; } -bool CAlert::ProcessAlert(bool fThread) +bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread) { - if (!CheckSignature()) + if (!CheckSignature(alertKey)) return false; if (!IsInEffect()) return false; diff --git a/src/alert.h b/src/alert.h index af42171af5..746967c4af 100644 --- a/src/alert.h +++ b/src/alert.h @@ -100,8 +100,8 @@ public: bool AppliesTo(int nVersion, std::string strSubVerIn) const; bool AppliesToMe() const; bool RelayTo(CNode* pnode) const; - bool CheckSignature() const; - bool ProcessAlert(bool fThread = true); // fThread means run -alertnotify in a free-running thread + bool CheckSignature(const std::vector<unsigned char>& alertKey) const; + bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread static void Notify(const std::string& strMessage, bool fThread); /* diff --git a/src/main.cpp b/src/main.cpp index 011016204e..8fb6766301 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3248,6 +3248,7 @@ void static CheckBlockIndex() CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid. CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA. CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not). + CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not). CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not). CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not). while (pindex != NULL) { @@ -3255,6 +3256,7 @@ void static CheckBlockIndex() if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex; if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex; if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex; + if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex; if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex; if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex; @@ -3264,7 +3266,12 @@ void static CheckBlockIndex() assert(pindex->GetBlockHash() == Params().HashGenesisBlock()); // Genesis block's hash must match. assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. } + // HAVE_DATA is equivalent to VALID_TRANSACTIONS and equivalent to nTx > 0 (we stored the number of transactions in the block) + assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); + assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); + // All parents having data is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set. assert((pindexFirstMissing != NULL) == (pindex->nChainTx == 0)); // nChainTx == 0 is used to signal that all parent block's transaction data is available. + assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0)); assert(pindex->nHeight == nHeight); // nHeight must be consistent. assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's. assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks. @@ -3320,6 +3327,7 @@ void static CheckBlockIndex() if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL; if (pindex == pindexFirstMissing) pindexFirstMissing = NULL; if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL; + if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL; if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL; if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL; // Find our parent. @@ -4262,7 +4270,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint256 alertHash = alert.GetHash(); if (pfrom->setKnown.count(alertHash) == 0) { - if (alert.ProcessAlert()) + if (alert.ProcessAlert(Params().AlertKey())) { // Relay pfrom->setKnown.insert(alertHash); diff --git a/src/pow.cpp b/src/pow.cpp index 3c5a8d9d96..cf7ac387f2 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -42,9 +42,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead } // Go back by what we want to be 14 days worth of blocks - const CBlockIndex* pindexFirst = pindexLast; - for (int i = 0; pindexFirst && i < params.DifficultyAdjustmentInterval()-1; i++) - pindexFirst = pindexFirst->pprev; + int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1); + assert(nHeightFirst >= 0); + const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst); assert(pindexFirst); return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params); diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index b1ed7a27b5..8911b41cbf 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -807,7 +807,7 @@ <string>collapse fee-settings</string> </property> <property name="text"> - <string>Minimize</string> + <string>Hide</string> </property> </widget> </item> diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 5e1f5f0294..6b6df5199a 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -10,6 +10,7 @@ #include "clientversion.h" #include "data/alertTests.raw.h" +#include "chainparams.h" #include "serialize.h" #include "streams.h" #include "util.h" @@ -119,10 +120,11 @@ BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts) BOOST_AUTO_TEST_CASE(AlertApplies) { SetMockTime(11); + const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); BOOST_FOREACH(const CAlert& alert, alerts) { - BOOST_CHECK(alert.CheckSignature()); + BOOST_CHECK(alert.CheckSignature(alertKey)); } BOOST_CHECK(alerts.size() >= 3); @@ -159,6 +161,7 @@ BOOST_AUTO_TEST_CASE(AlertApplies) BOOST_AUTO_TEST_CASE(AlertNotify) { SetMockTime(11); + const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); boost::filesystem::path temp = GetTempPath() / "alertnotify.txt"; boost::filesystem::remove(temp); @@ -166,7 +169,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify) mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); BOOST_FOREACH(CAlert alert, alerts) - alert.ProcessAlert(false); + alert.ProcessAlert(alertKey, false); std::vector<std::string> r = read_lines(temp); BOOST_CHECK_EQUAL(r.size(), 4u); diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp new file mode 100644 index 0000000000..0996e13c48 --- /dev/null +++ b/src/test/mempool_tests.cpp @@ -0,0 +1,104 @@ +// Copyright (c) 2011-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "main.h" +#include "txmempool.h" +#include "util.h" + +#include "test/test_bitcoin.h" + +#include <boost/test/unit_test.hpp> +#include <list> + +BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup) + +BOOST_AUTO_TEST_CASE(MempoolRemoveTest) +{ + // Test CTxMemPool::remove functionality + + // Parent transaction with three children, + // and three grand-children: + CMutableTransaction txParent; + txParent.vin.resize(1); + txParent.vin[0].scriptSig = CScript() << OP_11; + txParent.vout.resize(3); + for (int i = 0; i < 3; i++) + { + txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + txParent.vout[i].nValue = 33000LL; + } + CMutableTransaction txChild[3]; + for (int i = 0; i < 3; i++) + { + txChild[i].vin.resize(1); + txChild[i].vin[0].scriptSig = CScript() << OP_11; + txChild[i].vin[0].prevout.hash = txParent.GetHash(); + txChild[i].vin[0].prevout.n = i; + txChild[i].vout.resize(1); + txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + txChild[i].vout[0].nValue = 11000LL; + } + CMutableTransaction txGrandChild[3]; + for (int i = 0; i < 3; i++) + { + txGrandChild[i].vin.resize(1); + txGrandChild[i].vin[0].scriptSig = CScript() << OP_11; + txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash(); + txGrandChild[i].vin[0].prevout.n = 0; + txGrandChild[i].vout.resize(1); + txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; + txGrandChild[i].vout[0].nValue = 11000LL; + } + + + CTxMemPool testPool(CFeeRate(0)); + std::list<CTransaction> removed; + + // Nothing in pool, remove should do nothing: + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 0); + + // Just the parent: + testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1)); + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 1); + removed.clear(); + + // Parent, children, grandchildren: + testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1)); + for (int i = 0; i < 3; i++) + { + testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1)); + testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1)); + } + // Remove Child[0], GrandChild[0] should be removed: + testPool.remove(txChild[0], removed, true); + BOOST_CHECK_EQUAL(removed.size(), 2); + removed.clear(); + // ... make sure grandchild and child are gone: + testPool.remove(txGrandChild[0], removed, true); + BOOST_CHECK_EQUAL(removed.size(), 0); + testPool.remove(txChild[0], removed, true); + BOOST_CHECK_EQUAL(removed.size(), 0); + // Remove parent, all children/grandchildren should go: + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 5); + BOOST_CHECK_EQUAL(testPool.size(), 0); + removed.clear(); + + // Add children and grandchildren, but NOT the parent (simulate the parent being in a block) + for (int i = 0; i < 3; i++) + { + testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1)); + testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1)); + } + // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be + // put into the mempool (maybe because it is non-standard): + testPool.remove(txParent, removed, true); + BOOST_CHECK_EQUAL(removed.size(), 6); + BOOST_CHECK_EQUAL(testPool.size(), 0); + removed.clear(); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0d50660327..85ea3f77b5 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -444,6 +444,18 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem LOCK(cs); std::deque<uint256> txToRemove; txToRemove.push_back(origTx.GetHash()); + if (fRecursive && !mapTx.count(origTx.GetHash())) { + // If recursively removing but origTx isn't in the mempool + // be sure to remove any children that are in the pool. This can + // happen during chain re-orgs if origTx isn't re-accepted into + // the mempool for any reason. + for (unsigned int i = 0; i < origTx.vout.size(); i++) { + std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); + if (it == mapNextTx.end()) + continue; + txToRemove.push_back(it->second.ptx->GetHash()); + } + } while (!txToRemove.empty()) { uint256 hash = txToRemove.front(); |