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"))
58 if (!ledger->isImmutable())
61 assert(ledger->stateMap().getHash().isNonZero());
66 ledger->info().hash, ledger);
102 assert(ret->info().seq == index);
108 assert(ret->isImmutable());
111 return (ret->info().seq == index) ? ret :
nullptr;
122 assert(ret->isImmutable());
123 assert(ret->info().hash == hash);
132 assert(ret->isImmutable());
133 assert(ret->info().hash == hash);
135 assert(ret->info().hash == hash);
149 if (metaData !=
nullptr)
151 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx <<
": " << msg
152 <<
" is missing this transaction:\n"
157 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx <<
": " << msg
158 <<
" is missing this transaction.";
176 auto validMetaData = getMeta(validLedger, tx);
177 auto builtMetaData = getMeta(builtLedger, tx);
179 assert(validMetaData || builtMetaData);
181 if (validMetaData && builtMetaData)
183 auto const& validNodes = validMetaData->getNodes();
184 auto const& builtNodes = builtMetaData->getNodes();
186 bool const result_diff =
187 validMetaData->getResultTER() != builtMetaData->getResultTER();
189 bool const index_diff =
190 validMetaData->getIndex() != builtMetaData->getIndex();
192 bool const nodes_diff = validNodes != builtNodes;
194 if (!result_diff && !index_diff && !nodes_diff)
196 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
197 <<
": No apparent mismatches detected!";
203 if (result_diff && index_diff)
205 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
206 <<
": Different result and index!";
207 JLOG(j.
debug()) <<
" Built:"
208 <<
" Result: " << builtMetaData->getResult()
209 <<
" Index: " << builtMetaData->getIndex();
210 JLOG(j.
debug()) <<
" Valid:"
211 <<
" Result: " << validMetaData->getResult()
212 <<
" Index: " << validMetaData->getIndex();
214 else if (result_diff)
217 <<
"MISMATCH on TX " << tx <<
": Different result!";
218 JLOG(j.
debug()) <<
" Built:"
219 <<
" Result: " << builtMetaData->getResult();
220 JLOG(j.
debug()) <<
" Valid:"
221 <<
" Result: " << validMetaData->getResult();
226 <<
"MISMATCH on TX " << tx <<
": Different index!";
227 JLOG(j.
debug()) <<
" Built:"
228 <<
" Index: " << builtMetaData->getIndex();
229 JLOG(j.
debug()) <<
" Valid:"
230 <<
" Index: " << validMetaData->getIndex();
235 if (result_diff && index_diff)
237 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
238 <<
": Different result, index and nodes!";
239 JLOG(j.
debug()) <<
" Built:\n"
241 JLOG(j.
debug()) <<
" Valid:\n"
244 else if (result_diff)
246 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
247 <<
": Different result and nodes!";
250 <<
" Result: " << builtMetaData->getResult() <<
" Nodes:\n"
254 <<
" Result: " << validMetaData->getResult() <<
" Nodes:\n"
259 JLOG(j.
debug()) <<
"MISMATCH on TX " << tx
260 <<
": Different index and nodes!";
263 <<
" Index: " << builtMetaData->getIndex() <<
" Nodes:\n"
267 <<
" Index: " << validMetaData->getIndex() <<
" Nodes:\n"
273 <<
"MISMATCH on TX " << tx <<
": Different nodes!";
274 JLOG(j.
debug()) <<
" Built:"
277 JLOG(j.
debug()) <<
" Valid:"
288 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
289 <<
": Metadata Difference. Valid=\n"
295 JLOG(j.
error()) <<
"MISMATCH on TX " << tx
296 <<
": Metadata Difference. Built=\n"
308 for (
auto const& item : sm)
312 return lhs->key() < rhs->key();
325 assert(built != valid);
333 JLOG(
j_.
error()) <<
"MISMATCH cannot be analyzed:"
334 <<
" builtLedger: " <<
to_string(built) <<
" -> "
336 <<
" -> " << validLedger;
340 assert(
builtLedger->info().seq == validLedger->info().seq);
345 stream <<
"Valid: " <<
getJson({*validLedger, {}});
346 stream <<
"Consensus: " << consensus;
353 if (
builtLedger->info().parentHash != validLedger->info().parentHash)
355 JLOG(
j_.
error()) <<
"MISMATCH on prior ledger";
360 if (
builtLedger->info().closeTime != validLedger->info().closeTime)
362 JLOG(
j_.
error()) <<
"MISMATCH on close time";
366 if (builtConsensusHash && validatedConsensusHash)
368 if (builtConsensusHash != validatedConsensusHash)
370 <<
"MISMATCH on consensus transaction set "
371 <<
" built: " <<
to_string(*builtConsensusHash)
372 <<
" validated: " <<
to_string(*validatedConsensusHash);
374 JLOG(
j_.
error()) <<
"MISMATCH with same consensus transaction set: "
380 auto const validTx =
leaves(validLedger->txMap());
382 if (builtTx == validTx)
383 JLOG(
j_.
error()) <<
"MISMATCH with same " << builtTx.size()
386 JLOG(
j_.
error()) <<
"MISMATCH with " << builtTx.size() <<
" built and "
387 << validTx.size() <<
" valid transactions.";
393 auto b = builtTx.
begin();
394 auto v = validTx.begin();
395 while (b != builtTx.end() && v != validTx.end())
397 if ((*b)->key() < (*v)->key())
402 else if ((*b)->key() > (*v)->key())
404 log_one(*validLedger, (*v)->key(),
"built",
j_);
409 if ((*b)->slice() != (*v)->slice())
419 for (; b != builtTx.end(); ++b)
421 for (; v != validTx.end(); ++v)
422 log_one(*validLedger, (*v)->key(),
"built",
j_);
437 auto entry = std::make_shared<cv_entry>();
440 if (entry->validated && !entry->built)
442 if (entry->validated.value() != hash)
444 JLOG(
j_.
error()) <<
"MISMATCH: seq=" << index
445 <<
" validated:" << entry->validated.value()
449 entry->validated.value(),
451 entry->validatedConsensusHash,
457 JLOG(
j_.
debug()) <<
"MATCH: seq=" << index <<
" late";
461 entry->built.emplace(hash);
462 entry->builtConsensusHash.emplace(consensusHash);
463 entry->consensus.emplace(std::move(consensus));
477 auto entry = std::make_shared<cv_entry>();
480 if (entry->built && !entry->validated)
482 if (entry->built.value() != hash)
485 <<
"MISMATCH: seq=" << index
486 <<
" built:" << entry->built.value() <<
" then:" << hash;
488 entry->built.value(),
490 entry->builtConsensusHash,
492 entry->consensus.
value());
497 JLOG(
j_.
debug()) <<
"MATCH: seq=" << index;
501 entry->validated.emplace(hash);
502 entry->validatedConsensusHash = consensusHash;
515 it->second = ledgerHash;
527 if (!ledger || ledger->info().seq < seq)