Ledger::pointer LedgerHistory::getLedgerBySeq (std::uint32_t index) { { LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ()); std::map <std::uint32_t, uint256>::iterator it (mLedgersByIndex.find (index)); if (it != mLedgersByIndex.end ()) { uint256 hash = it->second; sl.unlock (); return getLedgerByHash (hash); } } Ledger::pointer ret (Ledger::loadByIndex (index)); if (!ret) return ret; assert (ret->getLedgerSeq () == index); { // Add this ledger to the local tracking by index LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ()); assert (ret->isImmutable ()); m_ledgers_by_hash.canonicalize (ret->getHash (), ret); mLedgersByIndex[ret->getLedgerSeq ()] = ret->getHash (); return (ret->getLedgerSeq () == index) ? ret : Ledger::pointer (); } }
Ledger::pointer LedgerHistory::getLedgerBySeq (uint32 index) { TaggedCache::ScopedLockType sl (mLedgersByHash.peekMutex (), __FILE__, __LINE__); std::map<uint32, uint256>::iterator it (mLedgersByIndex.find (index)); if (it != mLedgersByIndex.end ()) { uint256 hash = it->second; sl.unlock (); return getLedgerByHash (hash); } sl.unlock (); Ledger::pointer ret (Ledger::loadByIndex (index)); if (!ret) return ret; assert (ret->getLedgerSeq () == index); sl.lock (__FILE__, __LINE__); assert (ret->isImmutable ()); mLedgersByHash.canonicalize (ret->getHash (), ret); mLedgersByIndex[ret->getLedgerSeq ()] = ret->getHash (); return (ret->getLedgerSeq () == index) ? ret : Ledger::pointer (); }
void LedgerHistory::handleMismatch (LedgerHash const& built, LedgerHash const& valid) { assert (built != valid); ++mismatch_counter_; Ledger::pointer builtLedger = getLedgerByHash (built); Ledger::pointer validLedger = getLedgerByHash (valid); if (builtLedger && validLedger) { assert (builtLedger->getLedgerSeq() == validLedger->getLedgerSeq()); // Determine the mismatch reason // Distinguish Byzantine failure from transaction processing difference if (builtLedger->getParentHash() != validLedger->getParentHash()) { // Disagreement over prior ledger indicates sync issue WriteLog (lsERROR, LedgerMaster) << "MISMATCH on prior ledger"; } else if (builtLedger->getCloseTimeNC() != validLedger->getCloseTimeNC()) { // Disagreement over close time indicates Byzantine failure WriteLog (lsERROR, LedgerMaster) << "MISMATCH on close time"; } else { std::vector <uint256> builtTx, validTx; builtLedger->peekTransactionMap()->visitLeaves( std::bind (&addLeaf, std::ref (builtTx), std::placeholders::_1)); validLedger->peekTransactionMap()->visitLeaves( std::bind (&addLeaf, std::ref (validTx), std::placeholders::_1)); std::sort (builtTx.begin(), builtTx.end()); std::sort (validTx.begin(), validTx.end()); if (builtTx == validTx) { // Disagreement with same prior ledger, close time, and transactions // indicates a transaction processing difference WriteLog (lsERROR, LedgerMaster) << "MISMATCH with same " << builtTx.size() << " tx"; } else { std::vector <uint256> notBuilt, notValid; std::set_difference ( validTx.begin(), validTx.end(), builtTx.begin(), builtTx.end(), std::inserter (notBuilt, notBuilt.begin())); std::set_difference ( builtTx.begin(), builtTx.end(), validTx.begin(), validTx.end(), std::inserter (notValid, notValid.begin())); // This can be either a disagreement over the consensus // set or difference in which transactions were rejected // as invalid WriteLog (lsERROR, LedgerMaster) << "MISMATCH tx differ " << builtTx.size() << " built, " << validTx.size() << " valid"; for (auto const& t : notBuilt) { WriteLog (lsERROR, LedgerMaster) << "MISMATCH built without " << t; } for (auto const& t : notValid) { WriteLog (lsERROR, LedgerMaster) << "MISMATCH valid without " << t; } } } } else WriteLog (lsERROR, LedgerMaster) << "MISMATCH cannot be analyzed"; }