mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-25 13:07:27 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a016a5742 | ||
|
|
035caef50e | ||
|
|
089885286d | ||
|
|
23806111df |
No files matched your search
@@ -54,6 +54,10 @@ public:
|
||||
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
|
||||
}
|
||||
|
||||
// viewRef_ points into view_, so a copied or moved context would alias the original.
|
||||
ApplyContext(ApplyContext const&) = delete;
|
||||
ApplyContext(ApplyContext&&) = delete;
|
||||
|
||||
std::reference_wrapper<ServiceRegistry> registry;
|
||||
STTx const& tx;
|
||||
TER const preclaimResult;
|
||||
@@ -63,20 +67,20 @@ public:
|
||||
ApplyView&
|
||||
view()
|
||||
{
|
||||
return *view_; // NOLINT(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
return viewRef_.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] ApplyView const&
|
||||
view() const
|
||||
{
|
||||
return *view_; // NOLINT(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
return viewRef_.get();
|
||||
}
|
||||
|
||||
// VFALCO Unfortunately this is necessary
|
||||
RawView&
|
||||
rawView()
|
||||
{
|
||||
return *view_; // NOLINT(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
return viewRef_.get();
|
||||
}
|
||||
|
||||
[[nodiscard]] ApplyFlags const&
|
||||
@@ -91,8 +95,7 @@ public:
|
||||
void
|
||||
deliver(STAmount const& amount)
|
||||
{
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
view_->deliver(amount);
|
||||
viewRef_.get().deliver(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,8 +129,7 @@ public:
|
||||
void
|
||||
destroyXRP(XRPAmount const& fee)
|
||||
{
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
view_->rawDestroyXRP(fee);
|
||||
viewRef_.get().rawDestroyXRP(fee);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,16 +143,16 @@ public:
|
||||
ApplyViewContext
|
||||
getApplyViewContext()
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
view_.has_value(),
|
||||
"xrpl::ApplyContext::getApplyViewContext : view_ emplaced in constructor");
|
||||
return {.view = *view_, .tx = tx};
|
||||
return {.view = viewRef_.get(), .tx = tx};
|
||||
}
|
||||
|
||||
private:
|
||||
OpenView& base_;
|
||||
ApplyFlags flags_;
|
||||
std::optional<ApplyViewImpl> view_;
|
||||
// Always refers to the engaged view_. Reseated whenever view_ is re-emplaced, so the
|
||||
// accessors need no optional check.
|
||||
std::reference_wrapper<ApplyViewImpl> viewRef_;
|
||||
|
||||
// The ID of the batch transaction we are executing under, if set.
|
||||
std::optional<UInt256 const> parentBatchId_;
|
||||
|
||||
@@ -35,25 +35,25 @@ ApplyContext::ApplyContext(
|
||||
, journal(journal)
|
||||
, base_(base)
|
||||
, flags_(flags)
|
||||
, viewRef_(view_.emplace(&base_, flags_))
|
||||
, parentBatchId_(parentBatchId)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
parentBatchId.has_value() == ((flags_ & TapBatch) == TapBatch),
|
||||
"Parent Batch ID should be set if batch apply flag is set");
|
||||
view_.emplace(&base_, flags_);
|
||||
}
|
||||
|
||||
void
|
||||
ApplyContext::discard()
|
||||
{
|
||||
view_.emplace(&base_, flags_);
|
||||
viewRef_ = view_.emplace(&base_, flags_);
|
||||
}
|
||||
|
||||
std::optional<TxMeta>
|
||||
ApplyContext::apply(TER ter)
|
||||
{
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
|
||||
return view_->apply(base_, tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal);
|
||||
return viewRef_.get().apply(
|
||||
base_, tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -66,14 +66,14 @@ ApplyContext::addOrderBook(Book const& book)
|
||||
std::size_t
|
||||
ApplyContext::size()
|
||||
{
|
||||
return view_->size(); // NOLINT(bugprone-unchecked-optional-access)
|
||||
return viewRef_.get().size();
|
||||
}
|
||||
|
||||
void
|
||||
ApplyContext::visit(
|
||||
std::function<void(UInt256 const&, bool, SLE::ConstRef, SLE::ConstRef)> const& func)
|
||||
{
|
||||
view_->visit(base_, func); // NOLINT(bugprone-unchecked-optional-access)
|
||||
viewRef_.get().visit(base_, func);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -132,21 +132,8 @@ private:
|
||||
std::chrono::seconds effectiveOverlap = detail::kDefaultEffectiveOverlap;
|
||||
int expectedRefreshMin = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serve each configured list from its own publisher server, fetch them all
|
||||
* through one ValidatorSite and check what it reports for each site.
|
||||
*
|
||||
* @param good Directory the cache files are written to.
|
||||
* @param paths One server per entry, with what to serve and what to expect.
|
||||
* @param requestTimeout How long the ValidatorSite waits for a response
|
||||
* before it reports that the request took too long.
|
||||
*/
|
||||
void
|
||||
testFetchList(
|
||||
detail::DirGuard const& good,
|
||||
std::vector<FetchListConfig> const& paths,
|
||||
std::chrono::seconds requestTimeout = std::chrono::seconds{12})
|
||||
testFetchList(detail::DirGuard const& good, std::vector<FetchListConfig> const& paths)
|
||||
{
|
||||
testcase << "Fetch list - "
|
||||
<< boost::algorithm::join(
|
||||
@@ -224,10 +211,10 @@ private:
|
||||
|
||||
BEAST_EXPECT(trustedKeys.load({}, emptyCfgKeys, cfgPublishers));
|
||||
|
||||
// Normally, tests will only need a fraction of the default timeout,
|
||||
// but sometimes DNS resolution takes an inordinate amount of time, so
|
||||
// the test will just wait.
|
||||
auto sites = std::make_unique<ValidatorSite>(env.app(), journal, requestTimeout);
|
||||
// Normally, tests will only need a fraction of this time,
|
||||
// but sometimes DNS resolution takes an inordinate amount
|
||||
// of time, so the test will just wait.
|
||||
auto sites = std::make_unique<ValidatorSite>(env.app(), journal, 12s);
|
||||
|
||||
std::vector<std::string> uris;
|
||||
for (auto const& u : servers)
|
||||
@@ -599,19 +586,18 @@ public:
|
||||
.failApply = true,
|
||||
},
|
||||
});
|
||||
// timeout: the server answers 1s after the request times out
|
||||
// timeout
|
||||
testFetchList(
|
||||
good,
|
||||
{
|
||||
{
|
||||
.path = "/sleep/2",
|
||||
.path = "/sleep/13",
|
||||
.msg = "took too long",
|
||||
.ssl = ssl,
|
||||
.failFetch = true,
|
||||
.failApply = true,
|
||||
},
|
||||
},
|
||||
std::chrono::seconds{1});
|
||||
});
|
||||
// bad manifest format using known versions
|
||||
// * Retrieves a v1 formatted list claiming version 2
|
||||
testFetchList(
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <xrpl/ledger/CanonicalTXSet.h>
|
||||
#include <xrpl/ledger/Ledger.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
@@ -174,7 +173,7 @@ TxTest::getOpenLedger() const
|
||||
return *openLedger_;
|
||||
}
|
||||
|
||||
ReadView const&
|
||||
Ledger const&
|
||||
TxTest::getClosedLedger() const
|
||||
{
|
||||
return *closedLedger_;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/Ledger.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
@@ -299,7 +298,7 @@ public:
|
||||
* @brief Get the closed (base) ledger view.
|
||||
* @return A const reference to the closed ledger.
|
||||
*/
|
||||
[[nodiscard]] ReadView const&
|
||||
[[nodiscard]] Ledger const&
|
||||
getClosedLedger() const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/Ledger.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/protocol_autogen/transactions/AccountSet.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <helpers/Account.h>
|
||||
#include <helpers/TxTest.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl::test {
|
||||
|
||||
/**
|
||||
* A funded alice over an open ledger, plus a signed transaction to build an
|
||||
* ApplyContext around.
|
||||
*/
|
||||
class ApplyContextTests : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
TxTest env_;
|
||||
Account const alice_{"alice"};
|
||||
std::shared_ptr<STTx const> tx_;
|
||||
|
||||
ApplyContextTests()
|
||||
{
|
||||
env_.createAccount(alice_, XRP(10'000));
|
||||
transactions::AccountSetBuilder builder{alice_.id()};
|
||||
builder.setSequence(env_.getAccountRoot(alice_.id()).getSequence());
|
||||
builder.setFee(XRPAmount(10));
|
||||
tx_ = builder.build(alice_.pk(), alice_.sk()).getSTTx();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a ticket entry that is not in the ledger.
|
||||
*
|
||||
* @param seq The raw ticket sequence.
|
||||
* @return The new entry.
|
||||
*/
|
||||
SLE::pointer
|
||||
makeTicket(std::uint32_t seq) const
|
||||
{
|
||||
auto sle = std::make_shared<SLE>(keylet::ticket(alice_.id(), SeqProxy::rawTicket(seq)));
|
||||
sle->setAccountID(sfAccount, alice_.id());
|
||||
sle->setFieldU32(sfTicketSequence, seq);
|
||||
sle->setFieldU64(sfOwnerNode, 0);
|
||||
return sle;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ApplyContextTests, discard_drops_pending_state_and_keeps_the_context_usable)
|
||||
{
|
||||
ASSERT_NE(tx_, nullptr);
|
||||
// A closed base makes apply() produce metadata, which an open ledger
|
||||
// does not.
|
||||
OpenView open(&env_.getClosedLedger());
|
||||
ApplyContext ctx(env_.getServiceRegistry(), open, *tx_, tesSUCCESS, XRPAmount{10}, TapRetry);
|
||||
|
||||
// Buffer an inserted entry, a modified entry, destroyed drops and a
|
||||
// delivered amount through the context's own surface.
|
||||
auto const stale = makeTicket(1);
|
||||
ctx.view().insert(stale);
|
||||
auto const account = ctx.view().peek(keylet::account(alice_.id()));
|
||||
ASSERT_NE(account, nullptr);
|
||||
auto const baseSeq = account->getFieldU32(sfSequence);
|
||||
account->setFieldU32(sfSequence, baseSeq + 1);
|
||||
ctx.view().update(account);
|
||||
ctx.destroyXRP(XRPAmount{10});
|
||||
ctx.deliver(STAmount{XRPAmount{5}});
|
||||
ASSERT_EQ(ctx.size(), 2);
|
||||
|
||||
ctx.discard();
|
||||
|
||||
// Reads fall through to the open ledger again and the flags survive.
|
||||
EXPECT_EQ(ctx.size(), 0);
|
||||
EXPECT_FALSE(ctx.view().exists(keylet::unchecked(stale->key())));
|
||||
auto const reread = ctx.view().read(keylet::account(alice_.id()));
|
||||
ASSERT_NE(reread, nullptr);
|
||||
EXPECT_EQ(reread->getFieldU32(sfSequence), baseSeq);
|
||||
EXPECT_EQ(ctx.view().flags(), TapRetry);
|
||||
|
||||
// Only changes made after the discard reach the target view.
|
||||
auto const fresh = makeTicket(2);
|
||||
ctx.view().insert(fresh);
|
||||
ctx.destroyXRP(XRPAmount{3});
|
||||
auto const meta = ctx.apply(tesSUCCESS);
|
||||
ASSERT_TRUE(meta.has_value());
|
||||
EXPECT_FALSE(meta->getDeliveredAmount().has_value());
|
||||
EXPECT_FALSE(open.exists(keylet::unchecked(stale->key())));
|
||||
EXPECT_TRUE(open.exists(keylet::unchecked(fresh->key())));
|
||||
auto const applied = open.read(keylet::account(alice_.id()));
|
||||
ASSERT_NE(applied, nullptr);
|
||||
EXPECT_EQ(applied->getFieldU32(sfSequence), baseSeq);
|
||||
|
||||
// OpenView buffers the burn without touching its header, so flush into a
|
||||
// real Ledger to see it: 3 drops are gone, not 13.
|
||||
Ledger const& prev = env_.getClosedLedger();
|
||||
Ledger next(prev, prev.header().closeTime + prev.header().closeTimeResolution);
|
||||
open.apply(next);
|
||||
EXPECT_EQ(next.header().drops, prev.header().drops - XRPAmount{3});
|
||||
}
|
||||
|
||||
} // namespace xrpl::test
|
||||
Reference in new issue
Block a user