void PendingEnvelopes::addTxSet(Hash hash, uint64 lastSeenSlotIndex, TxSetFramePtr txset) { CLOG(TRACE, "Herder") << "Add TxSet " << hexAbbrev(hash); mTxSetCache.put(hash, std::make_pair(lastSeenSlotIndex, txset)); mTxSetFetcher.recv(hash); }
void PendingEnvelopes::discardSCPEnvelopesWithQSet(Hash hash) { CLOG(TRACE, "Herder") << "Discarding SCP Envelopes with SCPQSet " << hexAbbrev(hash); auto envelopes = mQuorumSetFetcher.fetchingFor(hash); for (auto& envelope : envelopes) discardSCPEnvelope(envelope); }
void PendingEnvelopes::addSCPQuorumSet(Hash hash, const SCPQuorumSet& q) { assert(isQuorumSetSane(q, false)); CLOG(TRACE, "Herder") << "Add SCPQSet " << hexAbbrev(hash); SCPQuorumSetPtr qset(new SCPQuorumSet(q)); mQsetCache.put(hash, qset); mQuorumSetFetcher.recv(hash); }
bool PendingEnvelopes::recvTxSet(Hash hash, TxSetFramePtr txset) { CLOG(TRACE, "Herder") << "Got TxSet " << hexAbbrev(hash); auto lastSeenSlotIndex = mTxSetFetcher.getLastSeenSlotIndex(hash); if (lastSeenSlotIndex == 0) { return false; } addTxSet(hash, lastSeenSlotIndex, txset); return true; }
void FutureBucket::startMerge(Application& app) { // NB: startMerge starts with FutureBucket in a half-valid state; the inputs // are live but the merge is not yet running. So you can't call checkState() // on entry, only on exit. assert(mState == FB_LIVE_INPUTS); std::shared_ptr<Bucket> curr = mInputCurrBucket; std::shared_ptr<Bucket> snap = mInputSnapBucket; std::vector<std::shared_ptr<Bucket>> shadows = mInputShadowBuckets; bool keepDeadEntries = mKeepDeadEntries; assert(curr); assert(snap); assert(!mOutputBucket.valid()); // Retain all buckets while being merged. They'll be freed by the // BucketManagers only after the merge is done and resolved. curr->setRetain(true); snap->setRetain(true); for (auto b : shadows) { b->setRetain(true); } CLOG(TRACE, "Bucket") << "Preparing merge of curr=" << hexAbbrev(curr->getHash()) << " with snap=" << hexAbbrev(snap->getHash()); BucketManager& bm = app.getBucketManager(); using task_t = std::packaged_task<std::shared_ptr<Bucket>()>; std::shared_ptr<task_t> task = std::make_shared<task_t>( [curr, snap, &bm, shadows, keepDeadEntries]() { CLOG(TRACE, "Bucket") << "Worker merging curr=" << hexAbbrev(curr->getHash()) << " with snap=" << hexAbbrev(snap->getHash()); auto res = Bucket::merge(bm, curr, snap, shadows, keepDeadEntries); CLOG(TRACE, "Bucket") << "Worker finished merging curr=" << hexAbbrev(curr->getHash()) << " with snap=" << hexAbbrev(snap->getHash()); return res; }); mOutputBucket = task->get_future().share(); app.getWorkerIOService().post(bind(&task_t::operator(), task)); checkState(); }
bool PendingEnvelopes::recvSCPQuorumSet(Hash hash, const SCPQuorumSet& q) { CLOG(TRACE, "Herder") << "Got SCPQSet " << hexAbbrev(hash); auto lastSeenSlotIndex = mQuorumSetFetcher.getLastSeenSlotIndex(hash); if (lastSeenSlotIndex <= 0) { return false; } if (isQuorumSetSane(q, false)) { addSCPQuorumSet(hash, q); return true; } else { discardSCPEnvelopesWithQSet(hash); return false; } }
bool ApplyLedgerChainWork::applyHistoryOfSingleLedger() { LedgerHeaderHistoryEntry hHeader; LedgerHeader& header = hHeader.header; if (!mHdrIn || !mHdrIn.readOne(hHeader)) { return false; } auto& lm = mApp.getLedgerManager(); auto const& lclHeader = lm.getLastClosedLedgerHeader(); // If we are >1 before LCL, skip if (header.ledgerSeq + 1 < lclHeader.header.ledgerSeq) { CLOG(DEBUG, "History") << "Catchup skipping old ledger " << header.ledgerSeq; return true; } // If we are one before LCL, check that we knit up with it if (header.ledgerSeq + 1 == lclHeader.header.ledgerSeq) { if (hHeader.hash != lclHeader.header.previousLedgerHash) { throw std::runtime_error( fmt::format("replay of {:s} failed to connect on hash of LCL " "predecessor {:s}", LedgerManager::ledgerAbbrev(hHeader), LedgerManager::ledgerAbbrev( lclHeader.header.ledgerSeq - 1, lclHeader.header.previousLedgerHash))); } CLOG(DEBUG, "History") << "Catchup at 1-before LCL (" << header.ledgerSeq << "), hash correct"; return true; } // If we are at LCL, check that we knit up with it if (header.ledgerSeq == lclHeader.header.ledgerSeq) { if (hHeader.hash != lm.getLastClosedLedgerHeader().hash) { mApplyLedgerFailure.Mark(); throw std::runtime_error( fmt::format("replay of {:s} at LCL {:s} disagreed on hash", LedgerManager::ledgerAbbrev(hHeader), LedgerManager::ledgerAbbrev(lclHeader))); } CLOG(DEBUG, "History") << "Catchup at LCL=" << header.ledgerSeq << ", hash correct"; return true; } // If we are past current, we can't catch up: fail. if (header.ledgerSeq != lclHeader.header.ledgerSeq + 1) { mApplyLedgerFailure.Mark(); throw std::runtime_error( fmt::format("replay overshot current ledger: {:d} > {:d}", header.ledgerSeq, lclHeader.header.ledgerSeq + 1)); } // If we do not agree about LCL hash, we can't catch up: fail. if (header.previousLedgerHash != lm.getLastClosedLedgerHeader().hash) { mApplyLedgerFailure.Mark(); throw std::runtime_error(fmt::format( "replay at current ledger {:s} disagreed on LCL hash {:s}", LedgerManager::ledgerAbbrev(header.ledgerSeq - 1, header.previousLedgerHash), LedgerManager::ledgerAbbrev(lclHeader))); } auto txset = getCurrentTxSet(); CLOG(DEBUG, "History") << "Ledger " << header.ledgerSeq << " has " << txset->size() << " transactions"; // We've verified the ledgerHeader (in the "trusted part of history" // sense) in CATCHUP_VERIFY phase; we now need to check that the // txhash we're about to apply is the one denoted by that ledger // header. if (header.scpValue.txSetHash != txset->getContentsHash()) { mApplyLedgerFailure.Mark(); throw std::runtime_error(fmt::format( "replay txset hash differs from txset hash in replay ledger: hash " "for txset for {:d} is {:s}, expected {:s}", header.ledgerSeq, hexAbbrev(txset->getContentsHash()), hexAbbrev(header.scpValue.txSetHash))); } LedgerCloseData closeData(header.ledgerSeq, txset, header.scpValue); lm.closeLedger(closeData); CLOG(DEBUG, "History") << "LedgerManager LCL:\n" << xdr::xdr_to_string( lm.getLastClosedLedgerHeader()); CLOG(DEBUG, "History") << "Replay header:\n" << xdr::xdr_to_string(hHeader); if (lm.getLastClosedLedgerHeader().hash != hHeader.hash) { mApplyLedgerFailure.Mark(); throw std::runtime_error(fmt::format( "replay of {:s} produced mismatched ledger hash {:s}", LedgerManager::ledgerAbbrev(hHeader), LedgerManager::ledgerAbbrev(lm.getLastClosedLedgerHeader()))); } mApplyLedgerSuccess.Mark(); mLastApplied = hHeader; return true; }