20 #include <ripple/app/ledger/LedgerHistory.h>
21 #include <ripple/app/ledger/LedgerToJson.h>
22 #include <ripple/basics/Log.h>
23 #include <ripple/basics/chrono.h>
24 #include <ripple/basics/contract.h>
25 #include <ripple/json/to_string.h>
31 #ifndef CACHED_LEDGER_NUM
32 #define CACHED_LEDGER_NUM 96
43 , collector_(collector)
44 , mismatch_counter_(collector->make_counter(
"ledger.history",
"mismatch"))
50 app_.journal(
"TaggedCache"))
51 , m_consensus_validated(
54 std::chrono::minutes{5},
56 app_.journal(
"TaggedCache"))
57 , j_(app.journal(
"LedgerHistory"))
64 if (!ledger->isImmutable())
67 assert(ledger->stateMap().getHash().isNonZero());
72 ledger->info().hash, ledger);
111 assert(ret->info().seq == index);
117 assert(ret->isImmutable());
120 return (ret->info().seq == index) ? ret :
nullptr;
131 assert(ret->isImmutable());
132 assert(ret->info().hash == hash);
141 assert(ret->isImmutable());
142 assert(ret->info().hash == hash);
144 assert(ret->info().hash == hash);
158 if (metaData !=
nullptr)
160 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx <<
": " << msg
161 <<
" is missing this transaction:\n"
166 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx <<
": " << msg
167 <<
" is missing this transaction.";
178 auto getMeta = [](
ReadView const& ledger,
183 return std::make_shared<TxMeta>(txID, ledger.
seq(), *meta);
186 auto validMetaData = getMeta(validLedger, tx);
187 auto builtMetaData = getMeta(builtLedger, tx);
188 assert(validMetaData !=
nullptr || builtMetaData !=
nullptr);
190 if (validMetaData !=
nullptr && builtMetaData !=
nullptr)
192 auto const& validNodes = validMetaData->getNodes();
193 auto const& builtNodes = builtMetaData->getNodes();
195 bool const result_diff =
196 validMetaData->getResultTER() != builtMetaData->getResultTER();
198 bool const index_diff =
199 validMetaData->getIndex() != builtMetaData->getIndex();
201 bool const nodes_diff = validNodes != builtNodes;
203 if (!result_diff && !index_diff && !nodes_diff)
205 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
206 <<
": No apparent mismatches detected!";
212 if (result_diff && index_diff)
214 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
215 <<
": Different result and index!";
216 JLOG(j.
debug()) <<
" Built:"
217 <<
" Result: " << builtMetaData->getResult()
218 <<
" Index: " << builtMetaData->getIndex();
219 JLOG(j.
debug()) <<
" Valid:"
220 <<
" Result: " << validMetaData->getResult()
221 <<
" Index: " << validMetaData->getIndex();
223 else if (result_diff)
226 <<
"MISMATCH on TX " << tx <<
": Different result!";
227 JLOG(j.
debug()) <<
" Built:"
228 <<
" Result: " << builtMetaData->getResult();
229 JLOG(j.
debug()) <<
" Valid:"
230 <<
" Result: " << validMetaData->getResult();
235 <<
"MISMATCH on TX " << tx <<
": Different index!";
236 JLOG(j.
debug()) <<
" Built:"
237 <<
" Index: " << builtMetaData->getIndex();
238 JLOG(j.
debug()) <<
" Valid:"
239 <<
" Index: " << validMetaData->getIndex();
244 if (result_diff && index_diff)
246 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
247 <<
": Different result, index and nodes!";
248 JLOG(j.
debug()) <<
" Built:\n"
250 JLOG(j.
debug()) <<
" Valid:\n"
253 else if (result_diff)
255 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
256 <<
": Different result and nodes!";
259 <<
" Result: " << builtMetaData->getResult() <<
" Nodes:\n"
263 <<
" Result: " << validMetaData->getResult() <<
" Nodes:\n"
268 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
269 <<
": Different index and nodes!";
272 <<
" Index: " << builtMetaData->getIndex() <<
" Nodes:\n"
276 <<
" Index: " << validMetaData->getIndex() <<
" Nodes:\n"
282 <<
"MISMATCH on TX " << tx <<
": Different nodes!";
283 JLOG(j.
debug()) <<
" Built:"
286 JLOG(j.
debug()) <<
" Valid:"
292 else if (validMetaData !=
nullptr)
294 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
295 <<
": Metadata Difference (built has none)\n"
300 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
301 <<
": Metadata Difference (valid has none)\n"
313 for (
auto const& item : sm)
317 return lhs->key() < rhs->key();
330 assert(built != valid);
338 JLOG(
j_.
error()) <<
"MISMATCH cannot be analyzed:"
339 <<
" builtLedger: " <<
to_string(built) <<
" -> "
341 <<
" -> " << validLedger;
345 assert(
builtLedger->info().seq == validLedger->info().seq);
350 stream <<
"Valid: " <<
getJson({*validLedger, {}});
351 stream <<
"Consensus: " << consensus;
358 if (
builtLedger->info().parentHash != validLedger->info().parentHash)
360 JLOG(
j_.
error()) <<
"MISMATCH on prior ledger";
365 if (
builtLedger->info().closeTime != validLedger->info().closeTime)
367 JLOG(
j_.
error()) <<
"MISMATCH on close time";
371 if (builtConsensusHash && validatedConsensusHash)
373 if (builtConsensusHash != validatedConsensusHash)
375 <<
"MISMATCH on consensus transaction set "
376 <<
" built: " <<
to_string(*builtConsensusHash)
377 <<
" validated: " <<
to_string(*validatedConsensusHash);
379 JLOG(
j_.
error()) <<
"MISMATCH with same consensus transaction set: "
385 auto const validTx =
leaves(validLedger->txMap());
387 if (builtTx == validTx)
388 JLOG(
j_.
error()) <<
"MISMATCH with same " << builtTx.size()
391 JLOG(
j_.
error()) <<
"MISMATCH with " << builtTx.size() <<
" built and "
392 << validTx.size() <<
" valid transactions.";
398 auto b = builtTx.
begin();
399 auto v = validTx.begin();
400 while (b != builtTx.end() && v != validTx.end())
402 if ((*b)->key() < (*v)->key())
407 else if ((*b)->key() > (*v)->key())
409 log_one(*validLedger, (*v)->key(),
"built",
j_);
414 if ((*b)->slice() != (*v)->slice())
424 for (; b != builtTx.end(); ++b)
426 for (; v != validTx.end(); ++v)
427 log_one(*validLedger, (*v)->key(),
"built",
j_);
442 auto entry = std::make_shared<cv_entry>();
445 if (entry->validated && !entry->built)
447 if (entry->validated.value() != hash)
449 JLOG(
j_.
error()) <<
"MISMATCH: seq=" << index
450 <<
" validated:" << entry->validated.value()
454 entry->validated.value(),
456 entry->validatedConsensusHash,
462 JLOG(
j_.
debug()) <<
"MATCH: seq=" << index <<
" late";
466 entry->built.emplace(hash);
467 entry->builtConsensusHash.emplace(consensusHash);
468 entry->consensus.emplace(std::move(consensus));
482 auto entry = std::make_shared<cv_entry>();
485 if (entry->built && !entry->validated)
487 if (entry->built.value() != hash)
490 <<
"MISMATCH: seq=" << index
491 <<
" built:" << entry->built.value() <<
" then:" << hash;
493 entry->built.value(),
495 entry->builtConsensusHash,
497 entry->consensus.
value());
502 JLOG(
j_.
debug()) <<
"MATCH: seq=" << index;
506 entry->validated.emplace(hash);
507 entry->validatedConsensusHash = consensusHash;
520 it->second = ledgerHash;
539 if (!ledger || ledger->info().seq < seq)