mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-05 17:56:49 +00:00
Compare commits
5 Commits
copilot/fi
...
dangell7/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34bbb1433c | ||
|
|
ccd0f8c6fd | ||
|
|
1599c1a672 | ||
|
|
763dd503be | ||
|
|
2f3558c610 |
13
.github/workflows/check-pr-description.yml
vendored
13
.github/workflows/check-pr-description.yml
vendored
@@ -5,8 +5,17 @@ on:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request:
|
||||
types: [opened, edited, reopened, synchronize, ready_for_review]
|
||||
branches: [develop]
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
branches:
|
||||
- develop
|
||||
- "release-*"
|
||||
- "release/*"
|
||||
- "staging/*"
|
||||
|
||||
jobs:
|
||||
check_description:
|
||||
|
||||
13
.github/workflows/check-pr-title.yml
vendored
13
.github/workflows/check-pr-title.yml
vendored
@@ -5,8 +5,17 @@ on:
|
||||
types:
|
||||
- checks_requested
|
||||
pull_request:
|
||||
types: [opened, edited, reopened, synchronize, ready_for_review]
|
||||
branches: [develop]
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
branches:
|
||||
- develop
|
||||
- "release-*"
|
||||
- "release/*"
|
||||
- "staging/*"
|
||||
|
||||
jobs:
|
||||
check_title:
|
||||
|
||||
@@ -26,10 +26,6 @@ This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-R
|
||||
|
||||
This section contains changes targeting a future version.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- `feature`: In admin-mode responses, the `vetoed` field is now always a boolean. Disabled obsolete amendments now have `"vetoed": true` and a new `"obsolete": true` field, instead of the previous `"vetoed": "Obsolete"` string value. This change improves type safety for API clients. Both `vetoed` and `obsolete` fields are only present in admin-mode responses for disabled amendments.
|
||||
|
||||
### Additions
|
||||
|
||||
- `ledger_entry`, `account_objects`: The `Delegate` ledger entry now includes an optional `DestinationNode` field, which stores the index into the authorized account's owner directory. This field is present on entries created after bidirectional directory tracking was introduced and may appear in RPC responses for those entries. ([#6681](https://github.com/XRPLF/rippled/pull/6681))
|
||||
|
||||
@@ -953,6 +953,21 @@
|
||||
#
|
||||
# Optional keys for NuDB and RocksDB:
|
||||
#
|
||||
# cache_size Size of cache for database records. Default is 16384.
|
||||
# Setting this value to 0 will use the default value.
|
||||
#
|
||||
# cache_age Length of time in minutes to keep database records
|
||||
# cached. Default is 5 minutes. Setting this value to
|
||||
# 0 will use the default value.
|
||||
#
|
||||
# Note: if cache_size or cache_age is not specified,
|
||||
# default values will be used for the unspecified
|
||||
# parameter.
|
||||
#
|
||||
# Note: the cache will not be created if online_delete
|
||||
# is specified, because the rotating NodeStore does
|
||||
# not use this cache).
|
||||
#
|
||||
# fast_load Boolean. If set, load the last persisted ledger
|
||||
# from disk upon process start before syncing to
|
||||
# the network. This is likely to improve performance
|
||||
|
||||
@@ -131,6 +131,10 @@ public:
|
||||
std::uint32_t ledgerSeq,
|
||||
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback);
|
||||
|
||||
/** Remove expired entries from the positive and negative caches. */
|
||||
virtual void
|
||||
sweep() = 0;
|
||||
|
||||
/** Gather statistics pertaining to read and write activities.
|
||||
*
|
||||
* @param obj Json object reference into which to place counters.
|
||||
|
||||
@@ -22,6 +22,32 @@ public:
|
||||
beast::Journal j)
|
||||
: Database(scheduler, readThreads, config, j), backend_(std::move(backend))
|
||||
{
|
||||
std::optional<int> cacheSize, cacheAge;
|
||||
|
||||
if (config.exists("cache_size"))
|
||||
{
|
||||
cacheSize = get<int>(config, "cache_size");
|
||||
if (cacheSize.value() < 0)
|
||||
Throw<std::runtime_error>("Specified negative value for cache_size");
|
||||
}
|
||||
|
||||
if (config.exists("cache_age"))
|
||||
{
|
||||
cacheAge = get<int>(config, "cache_age");
|
||||
if (cacheAge.value() < 0)
|
||||
Throw<std::runtime_error>("Specified negative value for cache_age");
|
||||
}
|
||||
|
||||
if (cacheSize.has_value() || cacheAge.has_value())
|
||||
{
|
||||
cache_ = std::make_shared<TaggedCache<uint256, NodeObject>>(
|
||||
"DatabaseNodeImp",
|
||||
cacheSize.value_or(0),
|
||||
std::chrono::minutes(cacheAge.value_or(0)),
|
||||
stopwatch(),
|
||||
j);
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
backend_,
|
||||
"xrpl::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null "
|
||||
@@ -73,7 +99,13 @@ public:
|
||||
std::uint32_t ledgerSeq,
|
||||
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback) override;
|
||||
|
||||
void
|
||||
sweep() override;
|
||||
|
||||
private:
|
||||
// Cache for database objects. This cache is not always initialized. Check
|
||||
// for null before using.
|
||||
std::shared_ptr<TaggedCache<uint256, NodeObject>> cache_;
|
||||
// Persistent key/value storage
|
||||
std::shared_ptr<Backend> backend_;
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@ public:
|
||||
void
|
||||
sync() override;
|
||||
|
||||
void
|
||||
sweep() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Backend> writableBackend_;
|
||||
std::shared_ptr<Backend> archiveBackend_;
|
||||
|
||||
@@ -435,7 +435,6 @@ JSS(node_write_retries); // out: GetCounts
|
||||
JSS(node_writes_delayed); // out::GetCounts
|
||||
JSS(nth); // out: RPC server_definitions
|
||||
JSS(obligations); // out: GatewayBalances
|
||||
JSS(obsolete); // out: AmendmentTableImpl
|
||||
JSS(offers); // out: NetworkOPs, AccountOffers, Subscribe
|
||||
JSS(offer_id); // out: insertNFTokenOfferID
|
||||
JSS(offline); // in: TransactionSign
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -19,6 +21,16 @@ namespace xrpl::permissioned_dex {
|
||||
bool
|
||||
accountInDomain(ReadView const& view, AccountID const& account, Domain const& domainID)
|
||||
{
|
||||
// Avoid constructing a zero-key PermissionedDomain keylet.
|
||||
// keylet::permissionedDomain(uint256) uses the DomainID as the ledger key.
|
||||
if (view.rules().enabled(fixCleanup3_2_0) && domainID == beast::kZero)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::permissioned_dex::accountInDomain : domainID is zero");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const sleDomain = view.read(keylet::permissionedDomain(domainID));
|
||||
if (!sleDomain)
|
||||
return false;
|
||||
|
||||
@@ -24,6 +24,13 @@ DatabaseNodeImp::store(NodeObjectType type, Blob&& data, uint256 const& hash, st
|
||||
|
||||
auto obj = NodeObject::createObject(type, std::move(data), hash);
|
||||
backend_->store(obj);
|
||||
if (cache_)
|
||||
{
|
||||
// After the store, replace a negative cache entry if there is one
|
||||
cache_->canonicalize(hash, obj, [](std::shared_ptr<NodeObject> const& n) {
|
||||
return n->getType() == NodeObjectType::Dummy;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -32,9 +39,25 @@ DatabaseNodeImp::asyncFetch(
|
||||
std::uint32_t ledgerSeq,
|
||||
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback)
|
||||
{
|
||||
if (cache_)
|
||||
{
|
||||
std::shared_ptr<NodeObject> const obj = cache_->fetch(hash);
|
||||
if (obj)
|
||||
{
|
||||
callback(obj->getType() == NodeObjectType::Dummy ? nullptr : obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Database::asyncFetch(hash, ledgerSeq, std::move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseNodeImp::sweep()
|
||||
{
|
||||
if (cache_)
|
||||
cache_->sweep();
|
||||
}
|
||||
|
||||
std::shared_ptr<NodeObject>
|
||||
DatabaseNodeImp::fetchNodeObject(
|
||||
uint256 const& hash,
|
||||
@@ -42,32 +65,58 @@ DatabaseNodeImp::fetchNodeObject(
|
||||
FetchReport& fetchReport,
|
||||
bool duplicate)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nodeObject = nullptr;
|
||||
Status status = Status::Ok;
|
||||
std::shared_ptr<NodeObject> nodeObject = cache_ ? cache_->fetch(hash) : nullptr;
|
||||
if (!nodeObject)
|
||||
{
|
||||
JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record not "
|
||||
<< (cache_ ? "cached" : "found");
|
||||
|
||||
try
|
||||
{
|
||||
status = backend_->fetch(hash, &nodeObject);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash
|
||||
<< ": Exception fetching from backend: " << e.what();
|
||||
rethrow();
|
||||
}
|
||||
Status status = Status::Ok;
|
||||
try
|
||||
{
|
||||
status = backend_->fetch(hash, &nodeObject);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash
|
||||
<< ": Exception fetching from backend: " << e.what();
|
||||
rethrow();
|
||||
}
|
||||
|
||||
switch (status)
|
||||
switch (status)
|
||||
{
|
||||
case Status::Ok:
|
||||
if (cache_)
|
||||
{
|
||||
if (nodeObject)
|
||||
{
|
||||
cache_->canonicalizeReplaceClient(hash, nodeObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto notFound = NodeObject::createObject(NodeObjectType::Dummy, {}, hash);
|
||||
cache_->canonicalizeReplaceClient(hash, notFound);
|
||||
if (notFound->getType() != NodeObjectType::Dummy)
|
||||
nodeObject = notFound;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Status::NotFound:
|
||||
break;
|
||||
case Status::DataCorrupt:
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted";
|
||||
break;
|
||||
default:
|
||||
JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result "
|
||||
<< static_cast<int>(status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
case Status::Ok:
|
||||
case Status::NotFound:
|
||||
break;
|
||||
case Status::DataCorrupt:
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted";
|
||||
break;
|
||||
default:
|
||||
JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result "
|
||||
<< static_cast<int>(status);
|
||||
break;
|
||||
JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record found in cache";
|
||||
if (nodeObject->getType() == NodeObjectType::Dummy)
|
||||
nodeObject.reset();
|
||||
}
|
||||
|
||||
if (nodeObject)
|
||||
|
||||
@@ -113,6 +113,12 @@ DatabaseRotatingImp::store(NodeObjectType type, Blob&& data, uint256 const& hash
|
||||
storeStats(1, nObj->getData().size());
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseRotatingImp::sweep()
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
std::shared_ptr<NodeObject>
|
||||
DatabaseRotatingImp::fetchNodeObject(
|
||||
uint256 const& hash,
|
||||
|
||||
@@ -94,6 +94,12 @@ OfferCreate::preflight(PreflightContext const& ctx)
|
||||
if (tx.isFlag(tfHybrid) && !tx.isFieldPresent(sfDomainID))
|
||||
return temINVALID_FLAG;
|
||||
|
||||
// A zero DomainID is invalid for a PermissionedDomain ledger entry because
|
||||
// keylet::permissionedDomain(uint256) uses the DomainID as the ledger key.
|
||||
if (auto const domainID = tx[~sfDomainID];
|
||||
ctx.rules.enabled(fixCleanup3_2_0) && domainID && *domainID == beast::kZero)
|
||||
return temMALFORMED;
|
||||
|
||||
bool const bImmediateOrCancel(tx.isFlag(tfImmediateOrCancel));
|
||||
bool const bFillOrKill(tx.isFlag(tfFillOrKill));
|
||||
|
||||
|
||||
@@ -125,6 +125,12 @@ Payment::preflight(PreflightContext const& ctx)
|
||||
if (!mpTokensV2 && isDstMPT && ctx.tx.isFieldPresent(sfPaths))
|
||||
return temMALFORMED;
|
||||
|
||||
// A zero DomainID is invalid for a PermissionedDomain ledger entry because
|
||||
// keylet::permissionedDomain(uint256) uses the DomainID as the ledger key.
|
||||
if (auto const domainID = tx[~sfDomainID];
|
||||
ctx.rules.enabled(fixCleanup3_2_0) && domainID && *domainID == beast::kZero)
|
||||
return temMALFORMED;
|
||||
|
||||
bool const partialPaymentAllowed = tx.isFlag(tfPartialPayment);
|
||||
bool const limitQuality = tx.isFlag(tfLimitQuality);
|
||||
bool const defaultPathsAllowed = !tx.isFlag(tfNoRippleDirect);
|
||||
|
||||
@@ -197,6 +197,20 @@ class PermissionedDEX_test : public beast::unit_test::Suite
|
||||
env.close();
|
||||
}
|
||||
|
||||
// test preflight - malformed DomainID being zero
|
||||
// Only test this with fixCleanup3_2_0 enabled. Without the fix,
|
||||
// an assert-enabled build can crash when Ledger::read() receives
|
||||
// a zero-key PermissionedDomain keylet.
|
||||
if (features[fixCleanup3_2_0])
|
||||
{
|
||||
Env env(*this, features);
|
||||
auto const& [gw_, domainOwner, alice_, bob_, carol_, USD, domainID, credType] =
|
||||
PermissionedDEX(env);
|
||||
|
||||
env(offer(bob_, XRP(10), USD(10)), Domain(uint256{}), Ter(temMALFORMED));
|
||||
env.close();
|
||||
}
|
||||
|
||||
// preclaim - someone outside of the domain cannot create domain offer
|
||||
{
|
||||
Env env(*this, features);
|
||||
@@ -396,6 +410,24 @@ class PermissionedDEX_test : public beast::unit_test::Suite
|
||||
env.close();
|
||||
}
|
||||
|
||||
// test preflight - malformed DomainID being zero
|
||||
// Only test this with fixCleanup3_2_0 enabled. Without the fix,
|
||||
// an assert-enabled build can crash when Ledger::read() receives
|
||||
// a zero-key PermissionedDomain keylet.
|
||||
if (features[fixCleanup3_2_0])
|
||||
{
|
||||
Env env(*this, features);
|
||||
auto const& [gw_, domainOwner, alice_, bob_, carol_, USD, domainID, credType] =
|
||||
PermissionedDEX(env);
|
||||
|
||||
env(pay(bob_, alice_, USD(10)),
|
||||
Path(~USD),
|
||||
Sendmax(XRP(10)),
|
||||
Domain(uint256{}),
|
||||
Ter(temMALFORMED));
|
||||
env.close();
|
||||
}
|
||||
|
||||
// preclaim - cannot send payment with non existent domain
|
||||
{
|
||||
Env env(*this, features);
|
||||
@@ -1772,7 +1804,9 @@ public:
|
||||
|
||||
// Test domain offer (w/o hybrid)
|
||||
testOfferCreate(all);
|
||||
testOfferCreate(all - fixCleanup3_2_0);
|
||||
testPayment(all);
|
||||
testPayment(all - fixCleanup3_2_0);
|
||||
testBookStep(all);
|
||||
testRippling(all);
|
||||
testOfferTokenIssuerInDomain(all);
|
||||
|
||||
@@ -520,6 +520,25 @@ public:
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Create NodeStore with two backends to allow online deletion of data.
|
||||
// Normally, SHAMapStoreImp handles all these details.
|
||||
auto nscfg = env.app().config().section(ConfigSection::nodeDatabase());
|
||||
|
||||
// Provide default values.
|
||||
if (!nscfg.exists("cache_size"))
|
||||
{
|
||||
nscfg.set(
|
||||
"cache_size",
|
||||
std::to_string(
|
||||
env.app().config().getValueFor(SizedItem::TreeCacheSize, std::nullopt)));
|
||||
}
|
||||
|
||||
if (!nscfg.exists("cache_age"))
|
||||
{
|
||||
nscfg.set(
|
||||
"cache_age",
|
||||
std::to_string(
|
||||
env.app().config().getValueFor(SizedItem::TreeCacheAge, std::nullopt)));
|
||||
}
|
||||
|
||||
NodeStoreScheduler scheduler(env.app().getJobQueue());
|
||||
|
||||
std::string const writableDb = "write";
|
||||
@@ -528,7 +547,6 @@ public:
|
||||
auto archiveBackend = makeBackendRotating(env, scheduler, archiveDb);
|
||||
|
||||
static constexpr int kReadThreads = 4;
|
||||
auto nscfg = env.app().config().section(ConfigSection::nodeDatabase());
|
||||
auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
|
||||
scheduler,
|
||||
kReadThreads,
|
||||
|
||||
@@ -166,15 +166,12 @@ class Feature_test : public beast::unit_test::Suite
|
||||
feature.isMember(jss::enabled) && !feature[jss::enabled].asBool(),
|
||||
feature[jss::name].asString() + " enabled");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::vetoed) && feature[jss::vetoed].isBool(),
|
||||
feature[jss::name].asString() + " vetoed is bool");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::vetoed].asBool() == (expectVeto || expectObsolete),
|
||||
feature[jss::name].asString() + " vetoed value");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::obsolete) && feature[jss::obsolete].isBool() &&
|
||||
feature[jss::obsolete].asBool() == expectObsolete,
|
||||
feature[jss::name].asString() + " obsolete");
|
||||
feature.isMember(jss::vetoed) && feature[jss::vetoed].isBool() == !expectObsolete &&
|
||||
(!feature[jss::vetoed].isBool() ||
|
||||
feature[jss::vetoed].asBool() == expectVeto) &&
|
||||
(feature[jss::vetoed].isBool() ||
|
||||
feature[jss::vetoed].asString() == "Obsolete"),
|
||||
feature[jss::name].asString() + " vetoed");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::supported) && feature[jss::supported].asBool(),
|
||||
feature[jss::name].asString() + " supported");
|
||||
@@ -306,9 +303,6 @@ class Feature_test : public beast::unit_test::Suite
|
||||
(*it).isMember(jss::supported) &&
|
||||
(*it)[jss::supported].asBool() == expectSupported,
|
||||
(*it)[jss::name].asString() + " supported");
|
||||
BEAST_EXPECTS(
|
||||
(*it).isMember(jss::obsolete) && (*it)[jss::obsolete].isBool(),
|
||||
(*it)[jss::name].asString() + " unknown obsolete");
|
||||
BEAST_EXPECT(!(*it).isMember(jss::vetoed));
|
||||
BEAST_EXPECT(!(*it).isMember(jss::majority));
|
||||
BEAST_EXPECT(!(*it).isMember(jss::count));
|
||||
@@ -378,15 +372,12 @@ class Feature_test : public beast::unit_test::Suite
|
||||
else
|
||||
{
|
||||
BEAST_EXPECTS(
|
||||
(*it).isMember(jss::vetoed) && (*it)[jss::vetoed].isBool(),
|
||||
(*it)[jss::name].asString() + " vetoed is bool");
|
||||
BEAST_EXPECTS(
|
||||
(*it)[jss::vetoed].asBool() == (expectVeto || expectObsolete),
|
||||
(*it)[jss::name].asString() + " vetoed value");
|
||||
BEAST_EXPECTS(
|
||||
(*it).isMember(jss::obsolete) && (*it)[jss::obsolete].isBool() &&
|
||||
(*it)[jss::obsolete].asBool() == expectObsolete,
|
||||
(*it)[jss::name].asString() + " obsolete");
|
||||
(*it).isMember(jss::vetoed) && (*it)[jss::vetoed].isBool() == !expectObsolete &&
|
||||
(!(*it)[jss::vetoed].isBool() ||
|
||||
(*it)[jss::vetoed].asBool() == expectVeto) &&
|
||||
((*it)[jss::vetoed].isBool() ||
|
||||
(*it)[jss::vetoed].asString() == "Obsolete"),
|
||||
(*it)[jss::name].asString() + " vetoed");
|
||||
}
|
||||
BEAST_EXPECTS(
|
||||
(*it).isMember(jss::supported) && (*it)[jss::supported].asBool() == expectSupported,
|
||||
@@ -456,15 +447,12 @@ class Feature_test : public beast::unit_test::Suite
|
||||
(expectVeto || expectObsolete) ^ feature.isMember(jss::majority),
|
||||
feature[jss::name].asString() + " majority");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::vetoed) && feature[jss::vetoed].isBool(),
|
||||
feature[jss::name].asString() + " vetoed is bool");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::vetoed].asBool() == (expectVeto || expectObsolete),
|
||||
feature[jss::name].asString() + " vetoed value");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::obsolete) && feature[jss::obsolete].isBool() &&
|
||||
feature[jss::obsolete].asBool() == expectObsolete,
|
||||
feature[jss::name].asString() + " obsolete");
|
||||
feature.isMember(jss::vetoed) && feature[jss::vetoed].isBool() == !expectObsolete &&
|
||||
(!feature[jss::vetoed].isBool() ||
|
||||
feature[jss::vetoed].asBool() == expectVeto) &&
|
||||
(feature[jss::vetoed].isBool() ||
|
||||
feature[jss::vetoed].asString() == "Obsolete"),
|
||||
feature[jss::name].asString() + " vetoed");
|
||||
BEAST_EXPECTS(feature.isMember(jss::count), feature[jss::name].asString() + " count");
|
||||
BEAST_EXPECTS(
|
||||
feature.isMember(jss::threshold), feature[jss::name].asString() + " threshold");
|
||||
@@ -554,9 +542,8 @@ class Feature_test : public beast::unit_test::Suite
|
||||
auto feature = *(jrr.begin());
|
||||
BEAST_EXPECTS(feature[jss::name] == featureName, "name");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool() == true, "vetoed");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::obsolete].isBool() && feature[jss::obsolete].asBool() == true, "obsolete");
|
||||
feature[jss::vetoed].isString() && feature[jss::vetoed].asString() == "Obsolete",
|
||||
"vetoed");
|
||||
|
||||
jrr = env.rpc("feature", featureName, "reject")[jss::result];
|
||||
if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
|
||||
@@ -567,9 +554,8 @@ class Feature_test : public beast::unit_test::Suite
|
||||
feature = *(jrr.begin());
|
||||
BEAST_EXPECTS(feature[jss::name] == featureName, "name");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool() == true, "vetoed");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::obsolete].isBool() && feature[jss::obsolete].asBool() == true, "obsolete");
|
||||
feature[jss::vetoed].isString() && feature[jss::vetoed].asString() == "Obsolete",
|
||||
"vetoed");
|
||||
|
||||
jrr = env.rpc("feature", featureName, "accept")[jss::result];
|
||||
if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
|
||||
@@ -580,9 +566,8 @@ class Feature_test : public beast::unit_test::Suite
|
||||
feature = *(jrr.begin());
|
||||
BEAST_EXPECTS(feature[jss::name] == featureName, "name");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool() == true, "vetoed");
|
||||
BEAST_EXPECTS(
|
||||
feature[jss::obsolete].isBool() && feature[jss::obsolete].asBool() == true, "obsolete");
|
||||
feature[jss::vetoed].isString() && feature[jss::vetoed].asString() == "Obsolete",
|
||||
"vetoed");
|
||||
|
||||
// anything other than accept or reject is an error
|
||||
jrr = env.rpc("feature", featureName, "maybe");
|
||||
|
||||
@@ -784,7 +784,7 @@ RCLConsensus::Adaptor::buildLCL(
|
||||
|
||||
// Update fee computations based on accepted txs
|
||||
using namespace std::chrono_literals;
|
||||
app_.getTxQ().processClosedLedger(app_, *built, roundTime > 5s);
|
||||
app_.getTxQ().processClosedLedger(app_, *built, roundTime > 2500ms);
|
||||
|
||||
// And stash the ledger in the ledger master
|
||||
if (ledgerMaster_.storeLedger(built))
|
||||
|
||||
@@ -998,6 +998,10 @@ public:
|
||||
JLOG(journal_.debug()) << "MasterTransaction sweep. Size before: " << oldMasterTxSize
|
||||
<< "; size after: " << masterTxCache.size();
|
||||
}
|
||||
{
|
||||
// Sweep NodeStore database cache(s), if enabled.
|
||||
getNodeStore().sweep();
|
||||
}
|
||||
{
|
||||
std::size_t const oldLedgerMasterCacheSize = getLedgerMaster().getFetchPackCacheSize();
|
||||
|
||||
|
||||
@@ -165,6 +165,22 @@ std::unique_ptr<NodeStore::Database>
|
||||
SHAMapStoreImp::makeNodeStore(int readThreads)
|
||||
{
|
||||
auto nscfg = app_.config().section(ConfigSection::nodeDatabase());
|
||||
|
||||
// Provide default values.
|
||||
if (!nscfg.exists("cache_size"))
|
||||
{
|
||||
nscfg.set(
|
||||
"cache_size",
|
||||
std::to_string(app_.config().getValueFor(SizedItem::TreeCacheSize, std::nullopt)));
|
||||
}
|
||||
|
||||
if (!nscfg.exists("cache_age"))
|
||||
{
|
||||
nscfg.set(
|
||||
"cache_age",
|
||||
std::to_string(app_.config().getValueFor(SizedItem::TreeCacheAge, std::nullopt)));
|
||||
}
|
||||
|
||||
std::unique_ptr<NodeStore::Database> db;
|
||||
|
||||
if (deleteInterval_ != 0u)
|
||||
@@ -254,6 +270,8 @@ SHAMapStoreImp::run()
|
||||
LedgerIndex lastRotated = stateDb_.getState().lastRotated;
|
||||
netOPs_ = &app_.getOPs();
|
||||
ledgerMaster_ = &app_.getLedgerMaster();
|
||||
fullBelowCache_ = &(*app_.getNodeFamily().getFullBelowCache());
|
||||
treeNodeCache_ = &(*app_.getNodeFamily().getTreeNodeCache());
|
||||
|
||||
if (advisoryDelete_)
|
||||
canDelete_ = stateDb_.getCanDelete();
|
||||
@@ -542,16 +560,16 @@ SHAMapStoreImp::clearCaches(LedgerIndex validatedSeq)
|
||||
// Also clear the FullBelowCache so its generation counter is bumped.
|
||||
// This prevents stale "full below" markers from persisting across
|
||||
// backend rotation/online deletion and interfering with SHAMap sync.
|
||||
app_.getNodeFamily().getFullBelowCache()->clear();
|
||||
fullBelowCache_->clear();
|
||||
}
|
||||
|
||||
void
|
||||
SHAMapStoreImp::freshenCaches()
|
||||
{
|
||||
if (freshenCache(*app_.getNodeFamily().getTreeNodeCache()))
|
||||
if (freshenCache(*treeNodeCache_))
|
||||
return;
|
||||
if (freshenCache(app_.getMasterTransaction().getCache()))
|
||||
return;
|
||||
|
||||
freshenCache(app_.getMasterTransaction().getCache());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
#include <xrpl/rdb/DatabaseCon.h>
|
||||
#include <xrpl/server/State.h>
|
||||
#include <xrpl/shamap/FullBelowCache.h>
|
||||
#include <xrpl/shamap/TreeNodeCache.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
@@ -93,6 +95,8 @@ private:
|
||||
// as of run() or before
|
||||
NetworkOPs* netOPs_ = nullptr;
|
||||
LedgerMaster* ledgerMaster_ = nullptr;
|
||||
FullBelowCache* fullBelowCache_ = nullptr;
|
||||
TreeNodeCache* treeNodeCache_ = nullptr;
|
||||
|
||||
static constexpr auto kNodeStoreName = "NodeStore";
|
||||
|
||||
|
||||
@@ -957,8 +957,7 @@ AmendmentTableImpl::injectJson(
|
||||
{
|
||||
if (fs.vote == AmendmentVote::Obsolete)
|
||||
{
|
||||
v[jss::vetoed] = true;
|
||||
v[jss::obsolete] = true;
|
||||
v[jss::vetoed] = "Obsolete";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -59,10 +59,10 @@ struct ConsensusParms
|
||||
std::size_t const minConsensusPct = 80;
|
||||
|
||||
//! The duration a ledger may remain idle before closing
|
||||
std::chrono::milliseconds const ledgerIdleInterval = std::chrono::seconds{15};
|
||||
std::chrono::milliseconds const ledgerIdleInterval = std::chrono::seconds{5};
|
||||
|
||||
//! The number of seconds we wait minimum to ensure participation
|
||||
std::chrono::milliseconds const ledgerMinConsensus = std::chrono::milliseconds{1950};
|
||||
std::chrono::milliseconds const ledgerMinConsensus = std::chrono::milliseconds{1000};
|
||||
|
||||
/** The maximum amount of time to spend pausing for laggards.
|
||||
*
|
||||
@@ -73,7 +73,7 @@ struct ConsensusParms
|
||||
std::chrono::milliseconds const ledgerMaxConsensus = std::chrono::seconds{15};
|
||||
|
||||
//! Minimum number of seconds to wait to ensure others have computed the LCL
|
||||
std::chrono::milliseconds const ledgerMinClose = std::chrono::seconds{2};
|
||||
std::chrono::milliseconds const ledgerMinClose = std::chrono::seconds{1};
|
||||
|
||||
//! How often we check state or change positions
|
||||
std::chrono::milliseconds const ledgerGRANULARITY = std::chrono::seconds{1};
|
||||
@@ -99,7 +99,7 @@ struct ConsensusParms
|
||||
twice the interval between proposals (0.7s) divided by
|
||||
the interval between mid and late consensus ([85-50]/100).
|
||||
*/
|
||||
std::chrono::milliseconds const avMinConsensusTime = std::chrono::seconds{5};
|
||||
std::chrono::milliseconds const avMinConsensusTime = std::chrono::seconds{2};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Avalanche tuning
|
||||
|
||||
@@ -209,7 +209,7 @@ public:
|
||||
|
||||
// Work queue limits
|
||||
int maxTransactions = 250;
|
||||
static constexpr int kMaxJobQueueTx = 1000;
|
||||
static constexpr int kMaxJobQueueTx = 100000;
|
||||
static constexpr int kMinJobQueueTx = 100;
|
||||
|
||||
// Amendment majority time
|
||||
|
||||
Reference in New Issue
Block a user