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>
35 , collector_(collector)
36 , mismatch_counter_(collector->make_counter(
"ledger.history",
"mismatch"))
42 app_.journal(
"TaggedCache"))
43 , m_consensus_validated(
48 app_.journal(
"TaggedCache"))
49 , j_(app.journal(
"LedgerHistory"))
56 if (!ledger->isImmutable())
59 assert(ledger->stateMap().getHash().isNonZero());
64 ledger->info().hash, ledger);
103 assert(ret->info().seq == index);
109 assert(ret->isImmutable());
112 return (ret->info().seq == index) ? ret :
nullptr;
123 assert(ret->isImmutable());
124 assert(ret->info().hash == hash);
133 assert(ret->isImmutable());
134 assert(ret->info().hash == hash);
136 assert(ret->info().hash == hash);
150 if (metaData !=
nullptr)
152 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx <<
": " << msg
153 <<
" is missing this transaction:\n"
158 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx <<
": " << msg
159 <<
" is missing this transaction.";
170 auto getMeta = [](
ReadView const& ledger,
175 return std::make_shared<TxMeta>(txID, ledger.
seq(), *meta);
178 auto validMetaData = getMeta(validLedger, tx);
179 auto builtMetaData = getMeta(builtLedger, tx);
180 assert(validMetaData !=
nullptr || builtMetaData !=
nullptr);
182 if (validMetaData !=
nullptr && builtMetaData !=
nullptr)
184 auto const& validNodes = validMetaData->getNodes();
185 auto const& builtNodes = builtMetaData->getNodes();
187 bool const result_diff =
188 validMetaData->getResultTER() != builtMetaData->getResultTER();
190 bool const index_diff =
191 validMetaData->getIndex() != builtMetaData->getIndex();
193 bool const nodes_diff = validNodes != builtNodes;
195 if (!result_diff && !index_diff && !nodes_diff)
197 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
198 <<
": No apparent mismatches detected!";
204 if (result_diff && index_diff)
206 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
207 <<
": Different result and index!";
208 JLOG(j.
debug()) <<
" Built:"
209 <<
" Result: " << builtMetaData->getResult()
210 <<
" Index: " << builtMetaData->getIndex();
211 JLOG(j.
debug()) <<
" Valid:"
212 <<
" Result: " << validMetaData->getResult()
213 <<
" Index: " << validMetaData->getIndex();
215 else if (result_diff)
218 <<
"MISMATCH on TX " << tx <<
": Different result!";
219 JLOG(j.
debug()) <<
" Built:"
220 <<
" Result: " << builtMetaData->getResult();
221 JLOG(j.
debug()) <<
" Valid:"
222 <<
" Result: " << validMetaData->getResult();
227 <<
"MISMATCH on TX " << tx <<
": Different index!";
228 JLOG(j.
debug()) <<
" Built:"
229 <<
" Index: " << builtMetaData->getIndex();
230 JLOG(j.
debug()) <<
" Valid:"
231 <<
" Index: " << validMetaData->getIndex();
236 if (result_diff && index_diff)
238 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
239 <<
": Different result, index and nodes!";
240 JLOG(j.
debug()) <<
" Built:\n"
242 JLOG(j.
debug()) <<
" Valid:\n"
245 else if (result_diff)
247 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
248 <<
": Different result and nodes!";
251 <<
" Result: " << builtMetaData->getResult() <<
" Nodes:\n"
255 <<
" Result: " << validMetaData->getResult() <<
" Nodes:\n"
260 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
261 <<
": Different index and nodes!";
264 <<
" Index: " << builtMetaData->getIndex() <<
" Nodes:\n"
268 <<
" Index: " << validMetaData->getIndex() <<
" Nodes:\n"
274 <<
"MISMATCH on TX " << tx <<
": Different nodes!";
275 JLOG(j.
debug()) <<
" Built:"
278 JLOG(j.
debug()) <<
" Valid:"
284 else if (validMetaData !=
nullptr)
286 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
287 <<
": Metadata Difference (built has none)\n"
292 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
293 <<
": Metadata Difference (valid has none)\n"
305 for (
auto const& item : sm)
309 return lhs->key() < rhs->key();
322 assert(built != valid);
330 JLOG(
j_.
error()) <<
"MISMATCH cannot be analyzed:"
331 <<
" builtLedger: " <<
to_string(built) <<
" -> "
333 <<
" -> " << validLedger;
337 assert(
builtLedger->info().seq == validLedger->info().seq);
342 stream <<
"Valid: " <<
getJson({*validLedger, {}});
343 stream <<
"Consensus: " << consensus;
350 if (
builtLedger->info().parentHash != validLedger->info().parentHash)
352 JLOG(
j_.
error()) <<
"MISMATCH on prior ledger";
357 if (
builtLedger->info().closeTime != validLedger->info().closeTime)
359 JLOG(
j_.
error()) <<
"MISMATCH on close time";
363 if (builtConsensusHash && validatedConsensusHash)
365 if (builtConsensusHash != validatedConsensusHash)
367 <<
"MISMATCH on consensus transaction set "
368 <<
" built: " <<
to_string(*builtConsensusHash)
369 <<
" validated: " <<
to_string(*validatedConsensusHash);
371 JLOG(
j_.
error()) <<
"MISMATCH with same consensus transaction set: "
377 auto const validTx =
leaves(validLedger->txMap());
379 if (builtTx == validTx)
380 JLOG(
j_.
error()) <<
"MISMATCH with same " << builtTx.size()
383 JLOG(
j_.
error()) <<
"MISMATCH with " << builtTx.size() <<
" built and "
384 << validTx.size() <<
" valid transactions.";
390 auto b = builtTx.
begin();
391 auto v = validTx.begin();
392 while (b != builtTx.end() && v != validTx.end())
394 if ((*b)->key() < (*v)->key())
399 else if ((*b)->key() > (*v)->key())
401 log_one(*validLedger, (*v)->key(),
"built",
j_);
406 if ((*b)->slice() != (*v)->slice())
416 for (; b != builtTx.end(); ++b)
418 for (; v != validTx.end(); ++v)
419 log_one(*validLedger, (*v)->key(),
"built",
j_);
434 auto entry = std::make_shared<cv_entry>();
437 if (entry->validated && !entry->built)
439 if (entry->validated.value() != hash)
441 JLOG(
j_.
error()) <<
"MISMATCH: seq=" << index
442 <<
" validated:" << entry->validated.value()
446 entry->validated.value(),
448 entry->validatedConsensusHash,
454 JLOG(
j_.
debug()) <<
"MATCH: seq=" << index <<
" late";
458 entry->built.emplace(hash);
459 entry->builtConsensusHash.emplace(consensusHash);
460 entry->consensus.emplace(std::move(consensus));
474 auto entry = std::make_shared<cv_entry>();
477 if (entry->built && !entry->validated)
479 if (entry->built.value() != hash)
482 <<
"MISMATCH: seq=" << index
483 <<
" built:" << entry->built.value() <<
" then:" << hash;
485 entry->built.value(),
487 entry->builtConsensusHash,
489 entry->consensus.
value());
494 JLOG(
j_.
debug()) <<
"MATCH: seq=" << index;
498 entry->validated.emplace(hash);
499 entry->validatedConsensusHash = consensusHash;
512 it->second = ledgerHash;
524 if (!ledger || ledger->info().seq < seq)