mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
Compare commits
3 Commits
pratik/ope
...
vvysokikh1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d6f821a99 | ||
|
|
283bc3ea39 | ||
|
|
ebc2a9a625 |
@@ -56,7 +56,10 @@ std::size_t constexpr oversizeMetaDataCap = 5200;
|
||||
/** The maximum number of entries per directory page */
|
||||
std::size_t constexpr dirNodeMaxEntries = 32;
|
||||
|
||||
/** The maximum number of pages allowed in a directory */
|
||||
/** The maximum number of pages allowed in a directory
|
||||
|
||||
Made obsolete by fixDirectoryLimit amendment.
|
||||
*/
|
||||
std::uint64_t constexpr dirNodeMaxPages = 262144;
|
||||
|
||||
/** The maximum number of items in an NFT page */
|
||||
|
||||
@@ -29,9 +29,8 @@
|
||||
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PriceOracleOrder, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMClawbackRounding, Supported::no, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace BuildInfo {
|
||||
// and follow the format described at http://semver.org/
|
||||
//------------------------------------------------------------------------------
|
||||
// clang-format off
|
||||
char const* const versionString = "2.6.1"
|
||||
char const* const versionString = "2.6.2-rc1"
|
||||
// clang-format on
|
||||
|
||||
#if defined(DEBUG) || defined(SANITIZER)
|
||||
|
||||
@@ -568,6 +568,39 @@ struct Credentials_test : public beast::unit_test::suite
|
||||
jle[jss::result][jss::node]["CredentialType"] ==
|
||||
strHex(std::string_view(credType)));
|
||||
}
|
||||
|
||||
{
|
||||
testcase("Credentials fail, directory full");
|
||||
std::uint32_t const issuerSeq{env.seq(issuer) + 1};
|
||||
env(ticket::create(issuer, 63));
|
||||
env.close();
|
||||
|
||||
// Everything below can only be tested on open ledger.
|
||||
auto const res1 = directory::bumpLastPage(
|
||||
env,
|
||||
directory::maximumPageIndex(env),
|
||||
keylet::ownerDir(issuer.id()),
|
||||
directory::adjustOwnerNode);
|
||||
BEAST_EXPECT(res1);
|
||||
|
||||
auto const jv = credentials::create(issuer, subject, credType);
|
||||
env(jv, ter(tecDIR_FULL));
|
||||
// Free one directory entry by using a ticket
|
||||
env(noop(issuer), ticket::use(issuerSeq + 40));
|
||||
|
||||
// Fill subject directory
|
||||
env(ticket::create(subject, 63));
|
||||
auto const res2 = directory::bumpLastPage(
|
||||
env,
|
||||
directory::maximumPageIndex(env),
|
||||
keylet::ownerDir(subject.id()),
|
||||
directory::adjustOwnerNode);
|
||||
BEAST_EXPECT(res2);
|
||||
env(jv, ter(tecDIR_FULL));
|
||||
|
||||
// End test
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1094,6 +1127,7 @@ struct Credentials_test : public beast::unit_test::suite
|
||||
testSuccessful(all);
|
||||
testCredentialsDelete(all);
|
||||
testCreateFailed(all);
|
||||
testCreateFailed(all - fixDirectoryLimit);
|
||||
testAcceptFailed(all);
|
||||
testDeleteFailed(all);
|
||||
testFeatureFailed(all - featureCredentials);
|
||||
|
||||
80
src/test/app/NetworkOPs_test.cpp
Normal file
80
src/test/app/NetworkOPs_test.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2020 Dev Null Productions
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/CaptureLogs.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
#include <xrpld/app/misc/HashRouter.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
class NetworkOPs_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testAllBadHeldTransactions();
|
||||
}
|
||||
|
||||
void
|
||||
testAllBadHeldTransactions()
|
||||
{
|
||||
// All trasactions are already marked as SF_BAD, and we should be able
|
||||
// to handle the case properly without an assertion failure
|
||||
testcase("No valid transactions in batch");
|
||||
|
||||
std::string logs;
|
||||
|
||||
{
|
||||
using namespace jtx;
|
||||
auto const alice = Account{"alice"};
|
||||
Env env{
|
||||
*this,
|
||||
envconfig(),
|
||||
std::make_unique<CaptureLogs>(&logs),
|
||||
beast::severities::kAll};
|
||||
env.memoize(env.master);
|
||||
env.memoize(alice);
|
||||
|
||||
auto const jtx = env.jt(ticket::create(alice, 1), seq(1), fee(10));
|
||||
|
||||
auto transacionId = jtx.stx->getTransactionID();
|
||||
env.app().getHashRouter().setFlags(
|
||||
transacionId, HashRouterFlags::HELD);
|
||||
|
||||
env(jtx, json(jss::Sequence, 1), ter(terNO_ACCOUNT));
|
||||
|
||||
env.app().getHashRouter().setFlags(
|
||||
transacionId, HashRouterFlags::BAD);
|
||||
|
||||
env.close();
|
||||
}
|
||||
|
||||
BEAST_EXPECT(
|
||||
logs.find("No transaction to process!") != std::string::npos);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(NetworkOPs, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <test/jtx/delivermin.h>
|
||||
#include <test/jtx/deposit.h>
|
||||
#include <test/jtx/did.h>
|
||||
#include <test/jtx/directory.h>
|
||||
#include <test/jtx/domain.h>
|
||||
#include <test/jtx/escrow.h>
|
||||
#include <test/jtx/fee.h>
|
||||
|
||||
81
src/test/jtx/directory.h
Normal file
81
src/test/jtx/directory.h
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_DIRECTORY_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_DIRECTORY_H_INCLUDED
|
||||
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace ripple::test::jtx {
|
||||
|
||||
/** Directory operations. */
|
||||
namespace directory {
|
||||
|
||||
enum Error {
|
||||
DirectoryRootNotFound,
|
||||
DirectoryTooSmall,
|
||||
DirectoryPageDuplicate,
|
||||
DirectoryPageNotFound,
|
||||
InvalidLastPage,
|
||||
AdjustmentError
|
||||
};
|
||||
|
||||
/// Move the position of the last page in the user's directory on open ledger to
|
||||
/// newLastPage. Requirements:
|
||||
/// - directory must have at least two pages (root and one more)
|
||||
/// - adjust should be used to update owner nodes of the objects affected
|
||||
/// - newLastPage must be greater than index of the last page in the directory
|
||||
///
|
||||
/// Use this to test tecDIR_FULL errors in open ledger.
|
||||
/// NOTE: effects will be DISCARDED on env.close()
|
||||
auto
|
||||
bumpLastPage(
|
||||
Env& env,
|
||||
std::uint64_t newLastPage,
|
||||
Keylet directory,
|
||||
std::function<bool(ApplyView&, uint256, std::uint64_t)> adjust)
|
||||
-> Expected<void, Error>;
|
||||
|
||||
/// Implementation of adjust for the most common ledger entry, i.e. one where
|
||||
/// page index is stored in sfOwnerNode (and only there). Pass this function
|
||||
/// to bumpLastPage if the last page of directory has only objects
|
||||
/// of this kind (e.g. ticket, DID, offer, deposit preauth, MPToken etc.)
|
||||
bool
|
||||
adjustOwnerNode(ApplyView& view, uint256 key, std::uint64_t page);
|
||||
|
||||
inline auto
|
||||
maximumPageIndex(Env const& env) -> std::uint64_t
|
||||
{
|
||||
if (env.enabled(fixDirectoryLimit))
|
||||
return std::numeric_limits<std::uint64_t>::max();
|
||||
return dirNodeMaxPages - 1;
|
||||
}
|
||||
|
||||
} // namespace directory
|
||||
|
||||
} // namespace ripple::test::jtx
|
||||
|
||||
#endif
|
||||
145
src/test/jtx/impl/directory.cpp
Normal file
145
src/test/jtx/impl/directory.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2025 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <test/jtx/directory.h>
|
||||
|
||||
#include <xrpld/ledger/Sandbox.h>
|
||||
|
||||
namespace ripple::test::jtx {
|
||||
|
||||
/** Directory operations. */
|
||||
namespace directory {
|
||||
|
||||
auto
|
||||
bumpLastPage(
|
||||
Env& env,
|
||||
std::uint64_t newLastPage,
|
||||
Keylet directory,
|
||||
std::function<bool(ApplyView&, uint256, std::uint64_t)> adjust)
|
||||
-> Expected<void, Error>
|
||||
{
|
||||
Expected<void, Error> res{};
|
||||
env.app().openLedger().modify(
|
||||
[&](OpenView& view, beast::Journal j) -> bool {
|
||||
Sandbox sb(&view, tapNONE);
|
||||
|
||||
// Find the root page
|
||||
auto sleRoot = sb.peek(directory);
|
||||
if (!sleRoot)
|
||||
{
|
||||
res = Unexpected<Error>(DirectoryRootNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find last page
|
||||
auto const lastIndex = sleRoot->getFieldU64(sfIndexPrevious);
|
||||
if (lastIndex == 0)
|
||||
{
|
||||
res = Unexpected<Error>(DirectoryTooSmall);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sb.exists(keylet::page(directory, newLastPage)))
|
||||
{
|
||||
res = Unexpected<Error>(DirectoryPageDuplicate);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastIndex >= newLastPage)
|
||||
{
|
||||
res = Unexpected<Error>(InvalidLastPage);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto slePage = sb.peek(keylet::page(directory, lastIndex));
|
||||
if (!slePage)
|
||||
{
|
||||
res = Unexpected<Error>(DirectoryPageNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy its data and delete the page
|
||||
auto indexes = slePage->getFieldV256(sfIndexes);
|
||||
auto prevIndex = slePage->at(~sfIndexPrevious);
|
||||
auto owner = slePage->at(~sfOwner);
|
||||
sb.erase(slePage);
|
||||
|
||||
// Create new page to replace slePage
|
||||
auto sleNew =
|
||||
std::make_shared<SLE>(keylet::page(directory, newLastPage));
|
||||
sleNew->setFieldH256(sfRootIndex, directory.key);
|
||||
sleNew->setFieldV256(sfIndexes, indexes);
|
||||
if (owner)
|
||||
sleNew->setAccountID(sfOwner, *owner);
|
||||
if (prevIndex)
|
||||
sleNew->setFieldU64(sfIndexPrevious, *prevIndex);
|
||||
sb.insert(sleNew);
|
||||
|
||||
// Adjust root previous and previous node's next
|
||||
sleRoot->setFieldU64(sfIndexPrevious, newLastPage);
|
||||
if (prevIndex.value_or(0) == 0)
|
||||
sleRoot->setFieldU64(sfIndexNext, newLastPage);
|
||||
else
|
||||
{
|
||||
auto slePrev = sb.peek(keylet::page(directory, *prevIndex));
|
||||
if (!slePrev)
|
||||
{
|
||||
res = Unexpected<Error>(DirectoryPageNotFound);
|
||||
return false;
|
||||
}
|
||||
slePrev->setFieldU64(sfIndexNext, newLastPage);
|
||||
sb.update(slePrev);
|
||||
}
|
||||
sb.update(sleRoot);
|
||||
|
||||
// Fixup page numbers in the objects referred by indexes
|
||||
if (adjust)
|
||||
for (auto const key : indexes)
|
||||
{
|
||||
if (!adjust(sb, key, newLastPage))
|
||||
{
|
||||
res = Unexpected<Error>(AdjustmentError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sb.apply(view);
|
||||
return true;
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
adjustOwnerNode(ApplyView& view, uint256 key, std::uint64_t page)
|
||||
{
|
||||
auto sle = view.peek({ltANY, key});
|
||||
if (sle && sle->isFieldPresent(sfOwnerNode))
|
||||
{
|
||||
sle->setFieldU64(sfOwnerNode, page);
|
||||
view.update(sle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace directory
|
||||
|
||||
} // namespace ripple::test::jtx
|
||||
@@ -23,9 +23,11 @@
|
||||
#include <xrpl/basics/random.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
@@ -490,6 +492,91 @@ struct Directory_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testDirectoryFull()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
Account alice("alice");
|
||||
|
||||
auto const testCase = [&, this](FeatureBitset features, auto setup) {
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env(*this, features);
|
||||
env.fund(XRP(20000), alice);
|
||||
env.close();
|
||||
|
||||
auto const [lastPage, full] = setup(env);
|
||||
|
||||
// Populate root page and last page
|
||||
for (int i = 0; i < 63; ++i)
|
||||
env(credentials::create(alice, alice, std::to_string(i)));
|
||||
env.close();
|
||||
|
||||
// NOTE, everything below can only be tested on open ledger because
|
||||
// there is no transaction type to express what bumpLastPage does.
|
||||
|
||||
// Bump position of last page from 1 to highest possible
|
||||
auto const res = directory::bumpLastPage(
|
||||
env,
|
||||
lastPage,
|
||||
keylet::ownerDir(alice.id()),
|
||||
[lastPage, this](
|
||||
ApplyView& view, uint256 key, std::uint64_t page) {
|
||||
auto sle = view.peek({ltCREDENTIAL, key});
|
||||
if (!BEAST_EXPECT(sle))
|
||||
return false;
|
||||
|
||||
BEAST_EXPECT(page == lastPage);
|
||||
sle->setFieldU64(sfIssuerNode, page);
|
||||
// sfSubjectNode is not set in self-issued credentials
|
||||
view.update(sle);
|
||||
return true;
|
||||
});
|
||||
BEAST_EXPECT(res);
|
||||
|
||||
// Create one more credential
|
||||
env(credentials::create(alice, alice, std::to_string(63)));
|
||||
|
||||
// Not enough space for another object if full
|
||||
auto const expected = full ? ter{tecDIR_FULL} : ter{tesSUCCESS};
|
||||
env(credentials::create(alice, alice, "foo"), expected);
|
||||
|
||||
// Destroy all objects in directory
|
||||
for (int i = 0; i < 64; ++i)
|
||||
env(credentials::deleteCred(
|
||||
alice, alice, alice, std::to_string(i)));
|
||||
|
||||
if (!full)
|
||||
env(credentials::deleteCred(alice, alice, alice, "foo"));
|
||||
|
||||
// Verify directory is empty.
|
||||
auto const sle = env.le(keylet::ownerDir(alice.id()));
|
||||
BEAST_EXPECT(sle == nullptr);
|
||||
|
||||
// Test completed
|
||||
env.close();
|
||||
};
|
||||
|
||||
testCase(
|
||||
testable_amendments() - fixDirectoryLimit,
|
||||
[this](Env&) -> std::tuple<std::uint64_t, bool> {
|
||||
testcase("directory full without fixDirectoryLimit");
|
||||
return {dirNodeMaxPages - 1, true};
|
||||
});
|
||||
testCase(
|
||||
testable_amendments(), //
|
||||
[this](Env&) -> std::tuple<std::uint64_t, bool> {
|
||||
testcase("directory not full with fixDirectoryLimit");
|
||||
return {dirNodeMaxPages - 1, false};
|
||||
});
|
||||
testCase(
|
||||
testable_amendments(), //
|
||||
[this](Env&) -> std::tuple<std::uint64_t, bool> {
|
||||
testcase("directory full with fixDirectoryLimit");
|
||||
return {std::numeric_limits<std::uint64_t>::max(), true};
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -498,6 +585,7 @@ struct Directory_test : public beast::unit_test::suite
|
||||
testRipd1353();
|
||||
testEmptyChain();
|
||||
testPreviousTxnID();
|
||||
testDirectoryFull();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1448,6 +1448,11 @@ NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set)
|
||||
for (auto& t : transactions)
|
||||
mTransactions.push_back(std::move(t));
|
||||
}
|
||||
if (mTransactions.empty())
|
||||
{
|
||||
JLOG(m_journal.debug()) << "No transaction to process!";
|
||||
return;
|
||||
}
|
||||
|
||||
doTransactionSyncBatch(lock, [&](std::unique_lock<std::mutex> const&) {
|
||||
XRPL_ASSERT(
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::optional<std::uint64_t>
|
||||
@@ -92,8 +95,21 @@ ApplyView::dirAdd(
|
||||
return page;
|
||||
}
|
||||
|
||||
// We rely on modulo arithmetic of unsigned integers (guaranteed in
|
||||
// [basic.fundamental] paragraph 2) to detect page representation overflow.
|
||||
// For signed integers this would be UB, hence static_assert here.
|
||||
static_assert(std::is_unsigned_v<decltype(page)>);
|
||||
// Defensive check against breaking changes in compiler.
|
||||
static_assert([]<typename T>(std::type_identity<T>) constexpr -> T {
|
||||
T tmp = std::numeric_limits<T>::max();
|
||||
return ++tmp;
|
||||
}(std::type_identity<decltype(page)>{}) == 0);
|
||||
++page;
|
||||
// Check whether we're out of pages.
|
||||
if (++page >= dirNodeMaxPages)
|
||||
if (page == 0)
|
||||
return std::nullopt;
|
||||
if (!rules().enabled(fixDirectoryLimit) &&
|
||||
page >= dirNodeMaxPages) // Old pages limit
|
||||
return std::nullopt;
|
||||
|
||||
// We are about to create a new node; we'll link it to
|
||||
|
||||
@@ -1286,8 +1286,7 @@ PeerImp::handleTransaction(
|
||||
|
||||
// Charge strongly for attempting to relay a txn with tfInnerBatchTxn
|
||||
// LCOV_EXCL_START
|
||||
if (stx->isFlag(tfInnerBatchTxn) &&
|
||||
getCurrentTransactionRules()->enabled(featureBatch))
|
||||
if (stx->isFlag(tfInnerBatchTxn))
|
||||
{
|
||||
JLOG(p_journal_.warn()) << "Ignoring Network relayed Tx containing "
|
||||
"tfInnerBatchTxn (handleTransaction).";
|
||||
@@ -2851,8 +2850,7 @@ PeerImp::checkTransaction(
|
||||
{
|
||||
// charge strongly for relaying batch txns
|
||||
// LCOV_EXCL_START
|
||||
if (stx->isFlag(tfInnerBatchTxn) &&
|
||||
getCurrentTransactionRules()->enabled(featureBatch))
|
||||
if (stx->isFlag(tfInnerBatchTxn))
|
||||
{
|
||||
JLOG(p_journal_.warn()) << "Ignoring Network relayed Tx containing "
|
||||
"tfInnerBatchTxn (checkSignature).";
|
||||
@@ -2866,6 +2864,9 @@ PeerImp::checkTransaction(
|
||||
(stx->getFieldU32(sfLastLedgerSequence) <
|
||||
app_.getLedgerMaster().getValidLedgerIndex()))
|
||||
{
|
||||
JLOG(p_journal_.info())
|
||||
<< "Marking transaction " << stx->getTransactionID()
|
||||
<< "as BAD because it's expired";
|
||||
app_.getHashRouter().setFlags(
|
||||
stx->getTransactionID(), HashRouterFlags::BAD);
|
||||
charge(Resource::feeUselessData, "expired tx");
|
||||
@@ -2922,7 +2923,7 @@ PeerImp::checkTransaction(
|
||||
{
|
||||
if (!validReason.empty())
|
||||
{
|
||||
JLOG(p_journal_.trace())
|
||||
JLOG(p_journal_.debug())
|
||||
<< "Exception checking transaction: " << validReason;
|
||||
}
|
||||
|
||||
@@ -2949,7 +2950,7 @@ PeerImp::checkTransaction(
|
||||
{
|
||||
if (!reason.empty())
|
||||
{
|
||||
JLOG(p_journal_.trace())
|
||||
JLOG(p_journal_.debug())
|
||||
<< "Exception checking transaction: " << reason;
|
||||
}
|
||||
app_.getHashRouter().setFlags(
|
||||
|
||||
Reference in New Issue
Block a user