20#include <xrpld/app/ledger/LedgerHistory.h> 
   21#include <xrpld/app/ledger/LedgerToJson.h> 
   23#include <xrpl/basics/Log.h> 
   24#include <xrpl/basics/chrono.h> 
   25#include <xrpl/basics/contract.h> 
   26#include <xrpl/json/to_string.h> 
   36    , collector_(collector)
 
   37    , mismatch_counter_(collector->make_counter(
"ledger.history", 
"mismatch"))
 
   43          app_.journal(
"TaggedCache"))
 
   44    , m_consensus_validated(
 
   47          std::chrono::minutes{5},
 
   49          app_.journal(
"TaggedCache"))
 
   50    , j_(app.journal(
"LedgerHistory"))
 
 
   59    if (!ledger->isImmutable())
 
   63        ledger->stateMap().getHash().isNonZero(),
 
   64        "ripple::LedgerHistory::insert : nonzero hash");
 
   69        ledger->info().hash, ledger);
 
 
  106        ret->info().seq == index,
 
  107        "ripple::LedgerHistory::getLedgerBySeq : result sequence match");
 
  115            "ripple::LedgerHistory::getLedgerBySeq : immutable result ledger");
 
  118        return (ret->info().seq == index) ? ret : 
nullptr;
 
 
  131            "ripple::LedgerHistory::getLedgerByHash : immutable fetched " 
  134            ret->info().hash == hash,
 
  135            "ripple::LedgerHistory::getLedgerByHash : fetched ledger hash " 
  147        "ripple::LedgerHistory::getLedgerByHash : immutable loaded ledger");
 
  149        ret->info().hash == hash,
 
  150        "ripple::LedgerHistory::getLedgerByHash : loaded ledger hash match");
 
  153        ret->info().hash == hash,
 
  154        "ripple::LedgerHistory::getLedgerByHash : result hash match");
 
 
  168    if (metaData != 
nullptr)
 
  170        JLOG(j.
debug()) << 
"MISMATCH on TX " << tx << 
": " << msg
 
  171                        << 
" is missing this transaction:\n" 
  176        JLOG(j.
debug()) << 
"MISMATCH on TX " << tx << 
": " << msg
 
  177                        << 
" is missing this transaction.";
 
 
  195    auto validMetaData = getMeta(validLedger, tx);
 
  196    auto builtMetaData = getMeta(builtLedger, tx);
 
  199        validMetaData || builtMetaData,
 
  200        "ripple::log_metadata_difference : some metadata present");
 
  202    if (validMetaData && builtMetaData)
 
  204        auto const& validNodes = validMetaData->getNodes();
 
  205        auto const& builtNodes = builtMetaData->getNodes();
 
  207        bool const result_diff =
 
  208            validMetaData->getResultTER() != builtMetaData->getResultTER();
 
  210        bool const index_diff =
 
  211            validMetaData->getIndex() != builtMetaData->getIndex();
 
  213        bool const nodes_diff = validNodes != builtNodes;
 
  215        if (!result_diff && !index_diff && !nodes_diff)
 
  217            JLOG(j.
error()) << 
"MISMATCH on TX " << tx
 
  218                            << 
": No apparent mismatches detected!";
 
  224            if (result_diff && index_diff)
 
  226                JLOG(j.
debug()) << 
"MISMATCH on TX " << tx
 
  227                                << 
": Different result and index!";
 
  228                JLOG(j.
debug()) << 
" Built:" 
  229                                << 
" Result: " << builtMetaData->getResult()
 
  230                                << 
" Index: " << builtMetaData->getIndex();
 
  231                JLOG(j.
debug()) << 
" Valid:" 
  232                                << 
" Result: " << validMetaData->getResult()
 
  233                                << 
" Index: " << validMetaData->getIndex();
 
  235            else if (result_diff)
 
  238                    << 
"MISMATCH on TX " << tx << 
": Different result!";
 
  239                JLOG(j.
debug()) << 
" Built:" 
  240                                << 
" Result: " << builtMetaData->getResult();
 
  241                JLOG(j.
debug()) << 
" Valid:" 
  242                                << 
" Result: " << validMetaData->getResult();
 
  247                    << 
"MISMATCH on TX " << tx << 
": Different index!";
 
  248                JLOG(j.
debug()) << 
" Built:" 
  249                                << 
" Index: " << builtMetaData->getIndex();
 
  250                JLOG(j.
debug()) << 
" Valid:" 
  251                                << 
" Index: " << validMetaData->getIndex();
 
  256            if (result_diff && index_diff)
 
  258                JLOG(j.
debug()) << 
"MISMATCH on TX " << tx
 
  259                                << 
": Different result, index and nodes!";
 
  260                JLOG(j.
debug()) << 
" Built:\n" 
  262                JLOG(j.
debug()) << 
" Valid:\n" 
  265            else if (result_diff)
 
  267                JLOG(j.
debug()) << 
"MISMATCH on TX " << tx
 
  268                                << 
": Different result and nodes!";
 
  271                    << 
" Result: " << builtMetaData->getResult() << 
" Nodes:\n" 
  275                    << 
" Result: " << validMetaData->getResult() << 
" Nodes:\n" 
  280                JLOG(j.
debug()) << 
"MISMATCH on TX " << tx
 
  281                                << 
": Different index and nodes!";
 
  284                    << 
" Index: " << builtMetaData->getIndex() << 
" Nodes:\n" 
  288                    << 
" Index: " << validMetaData->getIndex() << 
" Nodes:\n" 
  294                    << 
"MISMATCH on TX " << tx << 
": Different nodes!";
 
  295                JLOG(j.
debug()) << 
" Built:" 
  298                JLOG(j.
debug()) << 
" Valid:" 
  309        JLOG(j.
error()) << 
"MISMATCH on TX " << tx
 
  310                        << 
": Metadata Difference. Valid=\n" 
  316        JLOG(j.
error()) << 
"MISMATCH on TX " << tx
 
  317                        << 
": Metadata Difference. Built=\n" 
 
  329    for (
auto const& item : sm)
 
  333            return lhs->key() < rhs->key();
 
 
  348        "ripple::LedgerHistory::handleMismatch : unequal hashes");
 
  356        JLOG(
j_.
error()) << 
"MISMATCH cannot be analyzed:" 
  357                         << 
" builtLedger: " << 
to_string(built) << 
" -> " 
  359                         << 
" -> " << validLedger;
 
  364        builtLedger->info().seq == validLedger->info().seq,
 
  365        "ripple::LedgerHistory::handleMismatch : sequence match");
 
  370        stream << 
"Valid: " << 
getJson({*validLedger, {}});
 
  371        stream << 
"Consensus: " << consensus;
 
  378    if (
builtLedger->info().parentHash != validLedger->info().parentHash)
 
  380        JLOG(
j_.
error()) << 
"MISMATCH on prior ledger";
 
  385    if (
builtLedger->info().closeTime != validLedger->info().closeTime)
 
  387        JLOG(
j_.
error()) << 
"MISMATCH on close time";
 
  391    if (builtConsensusHash && validatedConsensusHash)
 
  393        if (builtConsensusHash != validatedConsensusHash)
 
  395                << 
"MISMATCH on consensus transaction set " 
  396                << 
" built: " << 
to_string(*builtConsensusHash)
 
  397                << 
" validated: " << 
to_string(*validatedConsensusHash);
 
  399            JLOG(
j_.
error()) << 
"MISMATCH with same consensus transaction set: " 
  405    auto const validTx = 
leaves(validLedger->txMap());
 
  407    if (builtTx == validTx)
 
  408        JLOG(
j_.
error()) << 
"MISMATCH with same " << builtTx.size()
 
  411        JLOG(
j_.
error()) << 
"MISMATCH with " << builtTx.size() << 
" built and " 
  412                         << validTx.size() << 
" valid transactions.";
 
  418    auto b = builtTx.
begin();
 
  419    auto v = validTx.begin();
 
  420    while (b != builtTx.end() && v != validTx.end())
 
  422        if ((*b)->key() < (*v)->key())
 
  427        else if ((*b)->key() > (*v)->key())
 
  429            log_one(*validLedger, (*v)->key(), 
"built", 
j_);
 
  434            if ((*b)->slice() != (*v)->slice())
 
  444    for (; b != builtTx.end(); ++b)
 
  446    for (; v != validTx.end(); ++v)
 
  447        log_one(*validLedger, (*v)->key(), 
"built", 
j_);
 
 
  459        !hash.
isZero(), 
"ripple::LedgerHistory::builtLedger : nonzero hash");
 
  466    if (entry->validated && !entry->built)
 
  468        if (entry->validated.value() != hash)
 
  470            JLOG(
j_.
error()) << 
"MISMATCH: seq=" << index
 
  471                             << 
" validated:" << entry->validated.value()
 
  475                entry->validated.value(),
 
  477                entry->validatedConsensusHash,
 
  483            JLOG(
j_.
debug()) << 
"MATCH: seq=" << index << 
" late";
 
  487    entry->built.emplace(hash);
 
  488    entry->builtConsensusHash.emplace(consensusHash);
 
  489    entry->consensus.emplace(std::move(consensus));
 
 
  501        "ripple::LedgerHistory::validatedLedger : nonzero hash");
 
  508    if (entry->built && !entry->validated)
 
  510        if (entry->built.value() != hash)
 
  513                << 
"MISMATCH: seq=" << index
 
  514                << 
" built:" << entry->built.value() << 
" then:" << hash;
 
  516                entry->built.value(),
 
  518                entry->builtConsensusHash,
 
  520                entry->consensus.value());
 
  525            JLOG(
j_.
debug()) << 
"MATCH: seq=" << index;
 
  529    entry->validated.emplace(hash);
 
  530    entry->validatedConsensusHash = consensusHash;
 
 
  543        it->second = ledgerHash;
 
 
  555        if (!ledger || ledger->info().seq < seq)
 
 
const_iterator begin() const
 
A generic endpoint for log messages.
 
LedgerHistory(beast::insight::Collector::ptr const &collector, Application &app)
 
std::map< LedgerIndex, LedgerHash > mLedgersByIndex
 
void builtLedger(std::shared_ptr< Ledger const > const &, uint256 const &consensusHash, Json::Value)
Report that we have locally built a particular ledger.
 
LedgersByHash m_ledgers_by_hash
 
ConsensusValidated m_consensus_validated
 
void handleMismatch(LedgerHash const &built, LedgerHash const &valid, std::optional< uint256 > const &builtConsensusHash, std::optional< uint256 > const &validatedConsensusHash, Json::Value const &consensus)
Log details in the case where we build one ledger but validate a different one.
 
LedgerHash getLedgerHash(LedgerIndex ledgerIndex)
Get a ledger's hash given its sequence number.
 
void clearLedgerCachePrior(LedgerIndex seq)
 
std::shared_ptr< Ledger const > getLedgerBySeq(LedgerIndex ledgerIndex)
Get a ledger given its sequence number.
 
beast::insight::Counter mismatch_counter_
 
bool insert(std::shared_ptr< Ledger const > const &ledger, bool validated)
Track a ledger.
 
bool fixIndex(LedgerIndex ledgerIndex, LedgerHash const &ledgerHash)
Repair a hash to index mapping.
 
void validatedLedger(std::shared_ptr< Ledger const > const &, std::optional< uint256 > const &consensusHash)
Report that we have validated a particular ledger.
 
std::shared_ptr< Ledger const > getLedgerByHash(LedgerHash const &ledgerHash)
Retrieve a ledger given its hash.
 
LedgerIndex seq() const
Returns the sequence number of the base ledger.
 
virtual tx_type txRead(key_type const &key) const =0
Read a transaction from the tx map.
 
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
 
bool canonicalize_replace_client(key_type const &key, SharedPointerType &data)
 
bool del(key_type const &key, bool valid)
 
SharedPointerType fetch(key_type const &key)
 
std::vector< key_type > getKeys() const
 
bool canonicalize_replace_cache(key_type const &key, SharedPointerType const &data)
 
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
std::shared_ptr< Ledger > loadByIndex(std::uint32_t ledgerIndex, Application &app, bool acquire)
 
static void log_one(ReadView const &ledger, uint256 const &tx, char const *msg, beast::Journal &j)
 
static std::vector< SHAMapItem const * > leaves(SHAMap const &sm)
 
std::shared_ptr< Ledger > loadByHash(uint256 const &ledgerHash, Application &app, bool acquire)
 
Stopwatch & stopwatch()
Returns an instance of a wall clock.
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
static void log_metadata_difference(ReadView const &builtLedger, ReadView const &validLedger, uint256 const &tx, beast::Journal j)
 
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
 
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.