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"))
47 , m_consensus_validated (
"ConsensusValidated", 64,
std::chrono::minutes {5},
49 , j_ (app.journal (
"LedgerHistory"))
58 if(! ledger->isImmutable())
61 assert (ledger->stateMap().getHash ().isNonZero ());
66 ledger->info().hash, ledger);
104 assert (ret->info().seq == index);
110 assert (ret->isImmutable ());
113 return (ret->info().seq == index) ? ret :
nullptr;
124 assert (ret->isImmutable ());
125 assert (ret->info().hash == hash);
134 assert (ret->isImmutable ());
135 assert (ret->info().hash == hash);
137 assert (ret->info().hash == hash);
152 if (metaData !=
nullptr)
154 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
155 ": " << msg <<
" is missing this transaction:\n" <<
160 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
161 ": " << msg <<
" is missing this transaction.";
173 auto getMeta = [](
ReadView const& ledger,
179 return std::make_shared<TxMeta> (txID, ledger.
seq(), *meta);
182 auto validMetaData = getMeta (validLedger, tx);
183 auto builtMetaData = getMeta (builtLedger, tx);
184 assert(validMetaData !=
nullptr || builtMetaData !=
nullptr);
186 if (validMetaData !=
nullptr && builtMetaData !=
nullptr)
188 auto const& validNodes = validMetaData->getNodes ();
189 auto const& builtNodes = builtMetaData->getNodes ();
191 bool const result_diff =
192 validMetaData->getResultTER () != builtMetaData->getResultTER ();
194 bool const index_diff =
195 validMetaData->getIndex() != builtMetaData->getIndex ();
197 bool const nodes_diff = validNodes != builtNodes;
199 if (!result_diff && !index_diff && !nodes_diff)
201 JLOG (j.
error()) <<
"MISMATCH on TX " << tx <<
202 ": No apparent mismatches detected!";
208 if (result_diff && index_diff)
210 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
211 ": Different result and index!";
212 JLOG (j.
debug()) <<
" Built:" <<
213 " Result: " << builtMetaData->getResult () <<
214 " Index: " << builtMetaData->getIndex ();
215 JLOG (j.
debug()) <<
" Valid:" <<
216 " Result: " << validMetaData->getResult () <<
217 " Index: " << validMetaData->getIndex ();
219 else if (result_diff)
221 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
222 ": Different result!";
223 JLOG (j.
debug()) <<
" Built:" <<
224 " Result: " << builtMetaData->getResult ();
225 JLOG (j.
debug()) <<
" Valid:" <<
226 " Result: " << validMetaData->getResult ();
230 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
231 ": Different index!";
232 JLOG (j.
debug()) <<
" Built:" <<
233 " Index: " << builtMetaData->getIndex ();
234 JLOG (j.
debug()) <<
" Valid:" <<
235 " Index: " << validMetaData->getIndex ();
240 if (result_diff && index_diff)
242 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
243 ": Different result, index and nodes!";
244 JLOG (j.
debug()) <<
" Built:\n" <<
246 JLOG (j.
debug()) <<
" Valid:\n" <<
249 else if (result_diff)
251 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
252 ": Different result and nodes!";
253 JLOG (j.
debug()) <<
" Built:" <<
254 " Result: " << builtMetaData->getResult () <<
256 JLOG (j.
debug()) <<
" Valid:" <<
257 " Result: " << validMetaData->getResult () <<
262 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
263 ": Different index and nodes!";
264 JLOG (j.
debug()) <<
" Built:" <<
265 " Index: " << builtMetaData->getIndex () <<
267 JLOG (j.
debug()) <<
" Valid:" <<
268 " Index: " << validMetaData->getIndex () <<
273 JLOG (j.
debug()) <<
"MISMATCH on TX " << tx <<
274 ": Different nodes!";
275 JLOG (j.
debug()) <<
" Built:" <<
277 JLOG (j.
debug()) <<
" Valid:" <<
282 else if (validMetaData !=
nullptr)
284 JLOG (j.
error()) <<
"MISMATCH on TX " << tx <<
285 ": Metadata Difference (built has none)\n" <<
290 JLOG (j.
error()) <<
"MISMATCH on TX " << tx <<
291 ": Metadata Difference (valid has none)\n" <<
304 for (
auto const& item : sm)
308 { return lhs->key() < rhs->key(); });
316 boost::optional<uint256>
const& builtConsensusHash,
317 boost::optional<uint256>
const& validatedConsensusHash,
320 assert (built != valid);
328 JLOG (
j_.
error()) <<
"MISMATCH cannot be analyzed:" <<
330 " validLedger: " <<
to_string (valid) <<
" -> " << validLedger;
334 assert (
builtLedger->info().seq == validLedger->info().seq);
339 stream <<
"Valid: " <<
getJson (*validLedger);
340 stream <<
"Consensus: " << consensus;
347 if (
builtLedger->info().parentHash != validLedger->info().parentHash)
349 JLOG (
j_.
error()) <<
"MISMATCH on prior ledger";
354 if (
builtLedger->info().closeTime != validLedger->info().closeTime)
356 JLOG (
j_.
error()) <<
"MISMATCH on close time";
360 if (builtConsensusHash && validatedConsensusHash)
362 if (builtConsensusHash != validatedConsensusHash)
364 <<
"MISMATCH on consensus transaction set "
365 <<
" built: " <<
to_string(*builtConsensusHash)
366 <<
" validated: " <<
to_string(*validatedConsensusHash);
368 JLOG(
j_.
error()) <<
"MISMATCH with same consensus transaction set: "
374 auto const validTx =
leaves(validLedger->txMap());
376 if (builtTx == validTx)
378 "MISMATCH with same " << builtTx.size() <<
381 JLOG (
j_.
error()) <<
"MISMATCH with " <<
382 builtTx.size() <<
" built and " <<
383 validTx.size() <<
" valid transactions.";
389 auto b = builtTx.begin();
390 auto v = validTx.begin();
391 while(b != builtTx.end() && v != validTx.end())
393 if ((*b)->key() < (*v)->key())
398 else if ((*b)->key() > (*v)->key())
400 log_one(*validLedger, (*v)->key(),
"built",
j_);
405 if ((*b)->peekData() != (*v)->peekData())
410 *validLedger, (*b)->key(),
j_);
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.get() != hash)
441 JLOG (
j_.
error()) <<
"MISMATCH: seq=" << index
442 <<
" validated:" << entry->validated.get()
446 entry->validated.get(),
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));
465 boost::optional<uint256>
const& consensusHash)
474 auto entry = std::make_shared<cv_entry>();
477 if (entry->built && ! entry->validated)
479 if (entry->built.get() != hash)
481 JLOG (
j_.
error()) <<
"MISMATCH: seq=" << index
482 <<
" built:" << entry->built.get()
487 entry->builtConsensusHash,
489 entry->consensus.get());
494 JLOG (
j_.
debug()) <<
"MATCH: seq=" << index;
498 entry->validated.emplace (hash);
499 entry->validatedConsensusHash = consensusHash;
512 it->second = ledgerHash;
529 if (!ledger || ledger->info().seq < seq)