diff --git a/include/xrpl/ledger/detail/ApplyStateTable.h b/include/xrpl/ledger/detail/ApplyStateTable.h index 07af5247f6..ca12e45b47 100644 --- a/include/xrpl/ledger/detail/ApplyStateTable.h +++ b/include/xrpl/ledger/detail/ApplyStateTable.h @@ -64,6 +64,11 @@ public: std::shared_ptr read(ReadView const& base, Keylet const& k) const; + /** Check only local items without delegating to base. + Returns std::nullopt if key not found locally. */ + std::optional> + readLocal(Keylet const& k) const; + std::shared_ptr peek(ReadView const& base, Keylet const& k); diff --git a/src/libxrpl/ledger/ApplyStateTable.cpp b/src/libxrpl/ledger/ApplyStateTable.cpp index 9892951e15..b71d02c271 100644 --- a/src/libxrpl/ledger/ApplyStateTable.cpp +++ b/src/libxrpl/ledger/ApplyStateTable.cpp @@ -330,24 +330,12 @@ ApplyStateTable::read(ReadView const& base, Keylet const& k) const return sle; } -std::shared_ptr -ApplyStateTable::peek(ReadView const& base, Keylet const& k) +std::optional> +ApplyStateTable::readLocal(Keylet const& k) const { - auto iter = items_.lower_bound(k.key); - if (iter == items_.end() || iter->first != k.key) - { - auto const sle = base.read(k); - if (!sle) - return nullptr; - // Make our own copy - using namespace std; - iter = items_.emplace_hint( - iter, - piecewise_construct, - forward_as_tuple(sle->key()), - forward_as_tuple(Action::cache, make_shared(*sle))); - return iter->second.second; - } + auto const iter = items_.find(k.key); + if (iter == items_.end()) + return std::nullopt; auto const& item = iter->second; auto const& sle = item.second; switch (item.first) @@ -361,6 +349,7 @@ ApplyStateTable::peek(ReadView const& base, Keylet const& k) }; if (!k.check(*sle)) return nullptr; + return sle; } diff --git a/src/libxrpl/ledger/ApplyViewBase.cpp b/src/libxrpl/ledger/ApplyViewBase.cpp index ecb5180557..2299decc32 100644 --- a/src/libxrpl/ledger/ApplyViewBase.cpp +++ b/src/libxrpl/ledger/ApplyViewBase.cpp @@ -48,7 +48,24 @@ ApplyViewBase::succ(key_type const& key, std::optional const& last) co std::shared_ptr ApplyViewBase::read(Keylet const& k) const { - return items_.read(*base_, k); + // Iteratively walk up the chain of ApplyViewBase layers + // instead of recursing through items_.read(*base_, k). + auto const* current = this; + while (current) + { + if (auto result = current->items_.readLocal(k)) + return *result; + + // Check if the base is another ApplyViewBase layer + auto const* next = dynamic_cast(current->base_); + if (!next) + return current->base_->read(k); + current = next; + } + // Unreachable: current starts as `this` (non-null) and the loop + // always returns before current could become null. + UNREACHABLE("xrpl::ApplyViewBase::read : unreachable"); + return nullptr; } auto