Fix few block processing bugs (#1291)

* protect mapRejectedBlocks by cs_main

* few block reprocessing fixes:
- DisconnectBlock should fail on DisconnectTip failure
- ResolveConflicts should fail on DisconnectBlock failure
- ReprocessBlocks cleanup

* don't ban on IsBlockValueValid/IsBlockPayeeValid failure
This commit is contained in:
UdjinM6 2017-01-30 10:01:08 +04:00 committed by GitHub
parent 04ed5db62c
commit e2eaf1d0d7
2 changed files with 25 additions and 16 deletions

View File

@ -540,7 +540,9 @@ bool CInstantSend::ResolveConflicts(const CTxLockCandidate& txLockCandidate, int
// Not in UTXO anymore? A conflicting tx was mined while we were waiting for votes. // Not in UTXO anymore? A conflicting tx was mined while we were waiting for votes.
// Reprocess tip to make sure tx for this lock is included. // Reprocess tip to make sure tx for this lock is included.
LogPrintf("CTxLockRequest::ResolveConflicts -- Failed to find UTXO %s - disconnecting tip...\n", txin.prevout.ToStringShort()); LogPrintf("CTxLockRequest::ResolveConflicts -- Failed to find UTXO %s - disconnecting tip...\n", txin.prevout.ToStringShort());
DisconnectBlocks(1); if(!DisconnectBlocks(1)) {
return false;
}
// Recursively check at "new" old height. Conflicting tx should be rejected by AcceptToMemoryPool. // Recursively check at "new" old height. Conflicting tx should be rejected by AcceptToMemoryPool.
ResolveConflicts(txLockCandidate, nMaxBlocks - 1); ResolveConflicts(txLockCandidate, nMaxBlocks - 1);
LogPrintf("CTxLockRequest::ResolveConflicts -- Failed to find UTXO %s - activating best chain...\n", txin.prevout.ToStringShort()); LogPrintf("CTxLockRequest::ResolveConflicts -- Failed to find UTXO %s - activating best chain...\n", txin.prevout.ToStringShort());

View File

@ -102,7 +102,7 @@ struct COrphanTx {
}; };
map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);; map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);;
map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);;
map<uint256, int64_t> mapRejectedBlocks; map<uint256, int64_t> mapRejectedBlocks GUARDED_BY(cs_main);
void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** /**
@ -2779,16 +2779,23 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
// DASH : MODIFYED TO CHECK MASTERNODE PAYMENTS AND SUPERBLOCKS // DASH : MODIFIED TO CHECK MASTERNODE PAYMENTS AND SUPERBLOCKS
// It's possible that we simply don't have enough data and this could fail
// (i.e. block itself could be a correct one and we need to store it),
// that's why this is in ConnectBlock. Could be the other way around however -
// the peer who sent us this block is missing some data and wasn't able
// to recognize that block is actually invalid.
// TODO: resync data (both ways?) and try to reprocess this block later.
CAmount blockReward = nFees + GetBlockSubsidy(pindex->pprev->nBits, pindex->pprev->nHeight, chainparams.GetConsensus()); CAmount blockReward = nFees + GetBlockSubsidy(pindex->pprev->nBits, pindex->pprev->nHeight, chainparams.GetConsensus());
std::string strError = ""; std::string strError = "";
if (!IsBlockValueValid(block, pindex->nHeight, blockReward, strError)) { if (!IsBlockValueValid(block, pindex->nHeight, blockReward, strError)) {
return state.DoS(100, error("ConnectBlock(): %s", strError), REJECT_INVALID, "bad-cb-amount"); return state.DoS(0, error("ConnectBlock(DASH): %s", strError), REJECT_INVALID, "bad-cb-amount");
} }
if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, blockReward)) { if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, blockReward)) {
mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime()));
return state.DoS(100, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"), return state.DoS(0, error("ConnectBlock(DASH): couldn't find masternode or superblock payments"),
REJECT_INVALID, "bad-cb-payee"); REJECT_INVALID, "bad-cb-payee");
} }
// END DASH // END DASH
@ -3162,21 +3169,25 @@ bool DisconnectBlocks(int blocks)
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
LogPrintf("DisconnectBlocks -- Got command to replay %d blocks\n", blocks); LogPrintf("DisconnectBlocks -- Got command to replay %d blocks\n", blocks);
for(int i = 0; i <= blocks; i++) for(int i = 0; i <= blocks; i++) {
DisconnectTip(state, chainparams.GetConsensus()); if(!DisconnectTip(state, chainparams.GetConsensus()) || !state.IsValid()) {
return false;
}
}
return true; return true;
} }
void ReprocessBlocks(int nBlocks) void ReprocessBlocks(int nBlocks)
{ {
LOCK(cs_main);
std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin(); std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin();
while(it != mapRejectedBlocks.end()){ while(it != mapRejectedBlocks.end()){
//use a window twice as large as is usual for the nBlocks we want to reset //use a window twice as large as is usual for the nBlocks we want to reset
if((*it).second > GetTime() - (nBlocks*60*5)) { if((*it).second > GetTime() - (nBlocks*60*5)) {
BlockMap::iterator mi = mapBlockIndex.find((*it).first); BlockMap::iterator mi = mapBlockIndex.find((*it).first);
if (mi != mapBlockIndex.end() && (*mi).second) { if (mi != mapBlockIndex.end() && (*mi).second) {
LOCK(cs_main);
CBlockIndex* pindex = (*mi).second; CBlockIndex* pindex = (*mi).second;
LogPrintf("ReprocessBlocks -- %s\n", (*it).first.ToString()); LogPrintf("ReprocessBlocks -- %s\n", (*it).first.ToString());
@ -3188,15 +3199,10 @@ void ReprocessBlocks(int nBlocks)
++it; ++it;
} }
CValidationState state; DisconnectBlocks(nBlocks);
{
LOCK(cs_main);
DisconnectBlocks(nBlocks);
}
if (state.IsValid()) { CValidationState state;
ActivateBestChain(state, Params()); ActivateBestChain(state, Params());
}
} }
/** /**
@ -3748,6 +3754,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// Relay corresponding transaction lock request and all its votes // Relay corresponding transaction lock request and all its votes
// to let other nodes complete the lock. // to let other nodes complete the lock.
instantsend.Relay(hashLocked); instantsend.Relay(hashLocked);
LOCK(cs_main);
mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime()));
return state.DoS(0, error("CheckBlock(DASH): transaction %s conflicts with transaction lock %s", return state.DoS(0, error("CheckBlock(DASH): transaction %s conflicts with transaction lock %s",
tx.GetHash().ToString(), hashLocked.ToString()), tx.GetHash().ToString(), hashLocked.ToString()),