Auto merge of #2101 - str4d:2074-tests, r=arcalinea

Bitcoin 0.12 test PRs 1

Cherry-picked from the following upstream PRs:

- bitcoin/bitcoin#6337
- bitcoin/bitcoin#6390
- bitcoin/bitcoin#5515
- bitcoin/bitcoin#6287 (partial, remainder included in bitcoin/bitcoin#6703)
- bitcoin/bitcoin#6465

Part of #2074.
This commit is contained in:
zkbot 2017-03-03 21:25:03 +00:00
commit dadb1ab74c
8 changed files with 67 additions and 26 deletions

View File

@ -140,8 +140,8 @@ class TestNode(NodeConnCB):
# or false, then only the last tx is tested against outcome.) # or false, then only the last tx is tested against outcome.)
class TestInstance(object): class TestInstance(object):
def __init__(self, objects=[], sync_every_block=True, sync_every_tx=False): def __init__(self, objects=None, sync_every_block=True, sync_every_tx=False):
self.blocks_and_transactions = objects self.blocks_and_transactions = objects if objects else []
self.sync_every_block = sync_every_block self.sync_every_block = sync_every_block
self.sync_every_tx = sync_every_tx self.sync_every_tx = sync_every_tx

View File

@ -985,6 +985,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
#ifdef ENABLE_MINING #ifdef ENABLE_MINING
if (mapArgs.count("-mineraddress")) { if (mapArgs.count("-mineraddress")) {
CBitcoinAddress addr; CBitcoinAddress addr;

View File

@ -79,9 +79,9 @@ struct COrphanTx {
CTransaction tx; CTransaction tx;
NodeId fromPeer; NodeId fromPeer;
}; };
map<uint256, COrphanTx> mapOrphanTransactions; map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev; map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);;
void EraseOrphansFor(NodeId peer); void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** /**
* Returns true if there are nRequired or more blocks of minVersion or above * Returns true if there are nRequired or more blocks of minVersion or above
@ -554,7 +554,7 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions // mapOrphanTransactions
// //
bool AddOrphanTx(const CTransaction& tx, NodeId peer) bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash)) if (mapOrphanTransactions.count(hash))
@ -584,7 +584,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer)
return true; return true;
} }
void static EraseOrphanTx(uint256 hash) void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash); map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end()) if (it == mapOrphanTransactions.end())
@ -618,7 +618,7 @@ void EraseOrphansFor(NodeId peer)
} }
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
unsigned int nEvicted = 0; unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans) while (mapOrphanTransactions.size() > nMaxOrphans)
@ -4131,7 +4131,7 @@ std::string GetWarnings(const std::string& strFor)
// //
bool static AlreadyHave(const CInv& inv) bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
switch (inv.type) switch (inv.type)
{ {

View File

@ -452,10 +452,19 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
if (!Params().MineBlocksOnDemand()) if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only"); throw runtime_error("setmocktime for regression testing (-regtest mode) only");
LOCK(cs_main); // cs_vNodes is locked and node send/receive times are updated
// atomically with the time change to prevent peers from being
// disconnected because we think we haven't communicated with them
// in a long time.
LOCK2(cs_main, cs_vNodes);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64()); SetMockTime(params[0].get_int64());
uint64_t t = GetTime();
BOOST_FOREACH(CNode* pnode, vNodes) {
pnode->nLastSend = pnode->nLastRecv = t;
}
return NullUniValue; return NullUniValue;
} }

View File

@ -33,20 +33,22 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
// //
struct CLockLocation { struct CLockLocation {
CLockLocation(const char* pszName, const char* pszFile, int nLine) CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
{ {
mutexName = pszName; mutexName = pszName;
sourceFile = pszFile; sourceFile = pszFile;
sourceLine = nLine; sourceLine = nLine;
fTry = fTryIn;
} }
std::string ToString() const std::string ToString() const
{ {
return mutexName + " " + sourceFile + ":" + itostr(sourceLine); return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
} }
std::string MutexName() const { return mutexName; } std::string MutexName() const { return mutexName; }
bool fTry;
private: private:
std::string mutexName; std::string mutexName;
std::string sourceFile; std::string sourceFile;
@ -62,23 +64,52 @@ static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{ {
// We attempt to not assert on probably-not deadlocks by assuming that
// a try lock will immediately have otherwise bailed if it had
// failed to get the lock
// We do this by, for the locks which triggered the potential deadlock,
// in either lockorder, checking that the second of the two which is locked
// is only a TRY_LOCK, ignoring locks if they are reentrant.
bool firstLocked = false;
bool secondLocked = false;
bool onlyMaybeDeadlock = false;
LogPrintf("POTENTIAL DEADLOCK DETECTED\n"); LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
LogPrintf("Previous lock order was:\n"); LogPrintf("Previous lock order was:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) { BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
if (i.first == mismatch.first) if (i.first == mismatch.first) {
LogPrintf(" (1)"); LogPrintf(" (1)");
if (i.first == mismatch.second) if (!firstLocked && secondLocked && i.second.fTry)
onlyMaybeDeadlock = true;
firstLocked = true;
}
if (i.first == mismatch.second) {
LogPrintf(" (2)"); LogPrintf(" (2)");
if (!secondLocked && firstLocked && i.second.fTry)
onlyMaybeDeadlock = true;
secondLocked = true;
}
LogPrintf(" %s\n", i.second.ToString()); LogPrintf(" %s\n", i.second.ToString());
} }
firstLocked = false;
secondLocked = false;
LogPrintf("Current lock order is:\n"); LogPrintf("Current lock order is:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) { BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
if (i.first == mismatch.first) if (i.first == mismatch.first) {
LogPrintf(" (1)"); LogPrintf(" (1)");
if (i.first == mismatch.second) if (!firstLocked && secondLocked && i.second.fTry)
onlyMaybeDeadlock = true;
firstLocked = true;
}
if (i.first == mismatch.second) {
LogPrintf(" (2)"); LogPrintf(" (2)");
if (!secondLocked && firstLocked && i.second.fTry)
onlyMaybeDeadlock = true;
secondLocked = true;
}
LogPrintf(" %s\n", i.second.ToString()); LogPrintf(" %s\n", i.second.ToString());
} }
assert(onlyMaybeDeadlock);
} }
static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
@ -101,10 +132,8 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
lockorders[p1] = (*lockstack); lockorders[p1] = (*lockstack);
std::pair<void*, void*> p2 = std::make_pair(c, i.first); std::pair<void*, void*> p2 = std::make_pair(c, i.first);
if (lockorders.count(p2)) { if (lockorders.count(p2))
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
break;
}
} }
} }
dd_mutex.unlock(); dd_mutex.unlock();
@ -119,7 +148,7 @@ static void pop_lock()
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{ {
push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
} }
void LeaveCritical() void LeaveCritical()

View File

@ -101,7 +101,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
/** Wrapper around boost::unique_lock<Mutex> */ /** Wrapper around boost::unique_lock<Mutex> */
template <typename Mutex> template <typename Mutex>
class CMutexLock class SCOPED_LOCKABLE CMutexLock
{ {
private: private:
boost::unique_lock<Mutex> lock; boost::unique_lock<Mutex> lock;
@ -129,7 +129,7 @@ private:
} }
public: public:
CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
{ {
if (fTry) if (fTry)
TryEnter(pszName, pszFile, nLine); TryEnter(pszName, pszFile, nLine);
@ -137,7 +137,7 @@ public:
Enter(pszName, pszFile, nLine); Enter(pszName, pszFile, nLine);
} }
CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{ {
if (!pmutexIn) return; if (!pmutexIn) return;
@ -148,7 +148,7 @@ public:
Enter(pszName, pszFile, nLine); Enter(pszName, pszFile, nLine);
} }
~CMutexLock() ~CMutexLock() UNLOCK_FUNCTION()
{ {
if (lock.owns_lock()) if (lock.owns_lock())
LeaveCritical(); LeaveCritical();

View File

@ -52,7 +52,7 @@
["-create", ["-create",
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
"set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]", "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
"sign=ALL", "sign=ALL",
"outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"], "outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"],
"output_cmp": "txcreatesign.hex" "output_cmp": "txcreatesign.hex"

View File

@ -1 +1 @@
01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d0000000000ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000 01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000