Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve transaction relay logic #4985

Open
wants to merge 77 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
c3805a7
Decrease `shouldRelay` limit to 30s:
ximinez Dec 21, 2023
36dddfa
Give a transaction more chances to be retried:
ximinez Jan 25, 2024
99a63a0
Pop all transactions with sequential sequences, or tickets
ximinez Jan 25, 2024
e048a41
Process held transactions through existing NetworkOPs batching:
ximinez Jan 25, 2024
3c0dbeb
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Apr 19, 2024
88c0074
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Apr 19, 2024
029d64c
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Apr 24, 2024
a1218af
Merge branch 'develop' into relay
ximinez Apr 26, 2024
f67f346
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Apr 26, 2024
3863b01
Merge remote-tracking branch 'upstream/develop' into relay
ximinez May 1, 2024
8b43ea8
Merge remote-tracking branch 'upstream/develop' into relay
ximinez May 7, 2024
23636d1
Merge commit 'c706926' into relay
ximinez Jul 2, 2024
7096d0a
Merge commit 'f6879da' into relay
ximinez Jul 2, 2024
643ca1a
Move CMake directory
Jul 2, 2024
f0170d3
Rearrange sources
Jul 2, 2024
8742e3b
Rewrite includes
Jul 2, 2024
e6f2597
Recompute loops
Jul 2, 2024
0f71e1c
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 2, 2024
31a18f8
Fix formatting
ximinez Jul 2, 2024
58a5797
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 5, 2024
05e4164
[FOLD] Review feedback from @scottschurr:
ximinez Jul 9, 2024
ff27e9e
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 10, 2024
5d1ab36
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 19, 2024
43d8ab1
fixup! [FOLD] Review feedback from @scottschurr:
ximinez Jul 21, 2024
c7e08bc
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 24, 2024
3054f5a
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 25, 2024
c9eed68
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jul 29, 2024
3ac1a8a
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Aug 2, 2024
0940acd
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Aug 6, 2024
00e1945
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Aug 8, 2024
77138fc
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Aug 19, 2024
c2f600c
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Sep 5, 2024
29dbd50
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Sep 11, 2024
3d741e1
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Sep 11, 2024
fb0e201
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Sep 25, 2024
f982d93
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Oct 15, 2024
284399b
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Oct 18, 2024
03f9d0f
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Oct 31, 2024
31e982a
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Oct 31, 2024
0641f77
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Nov 4, 2024
01bd73b
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Nov 5, 2024
f3e3199
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Nov 8, 2024
b056f25
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Nov 13, 2024
0bbb61a
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Nov 13, 2024
b008dbc
Add UNDOCUMENTED configuration section for HashRouter timeouts
ximinez Nov 13, 2024
022142f
Document why a lock is not used for Transaction::mApplying
ximinez Nov 14, 2024
be52629
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Nov 27, 2024
12af9f1
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Dec 3, 2024
c1866d1
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Dec 5, 2024
79fb1cc
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Dec 16, 2024
b5624fe
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Dec 20, 2024
a35aab0
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jan 7, 2025
9595d8c
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jan 9, 2025
eeb1277
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jan 24, 2025
91d0867
fixup! Add UNDOCUMENTED configuration section for HashRouter timeouts
ximinez Jan 28, 2025
3c5e9cf
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jan 28, 2025
2ca015e
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Jan 30, 2025
65303b3
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 4, 2025
e5233f2
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 6, 2025
8f48d64
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 7, 2025
d5ba2c6
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 8, 2025
dcc3ca5
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 11, 2025
d3a9522
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 12, 2025
9082414
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 13, 2025
96f9219
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 14, 2025
c94bf7d
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 20, 2025
9fe23dc
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 20, 2025
e96745f
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 25, 2025
1cd33b8
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 25, 2025
158c285
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 27, 2025
5b09745
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 27, 2025
e8c0d7b
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Feb 28, 2025
76dd4e1
Address review feedback from @Bronek:
ximinez Feb 28, 2025
47da138
Add missing include
ximinez Mar 1, 2025
93b9a6d
Get rid of some unused variables
ximinez Mar 1, 2025
0855726
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Mar 11, 2025
1fed810
Merge remote-tracking branch 'upstream/develop' into relay
ximinez Mar 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions src/test/app/HashRouter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,21 @@ namespace test {

class HashRouter_test : public beast::unit_test::suite
{
HashRouter::Setup
getSetup(std::chrono::seconds hold, std::chrono::seconds relay)
{
HashRouter::Setup setup;
setup.holdTime = hold;
setup.relayTime = relay;
return setup;
}

void
testNonExpiration()
{
using namespace std::chrono_literals;
TestStopwatch stopwatch;
HashRouter router(stopwatch, 2s);
HashRouter router(getSetup(2s, 1s), stopwatch);

uint256 const key1(1);
uint256 const key2(2);
Expand Down Expand Up @@ -68,7 +77,7 @@ class HashRouter_test : public beast::unit_test::suite
{
using namespace std::chrono_literals;
TestStopwatch stopwatch;
HashRouter router(stopwatch, 2s);
HashRouter router(getSetup(2s, 1s), stopwatch);

uint256 const key1(1);
uint256 const key2(2);
Expand Down Expand Up @@ -146,7 +155,7 @@ class HashRouter_test : public beast::unit_test::suite
// Normal HashRouter
using namespace std::chrono_literals;
TestStopwatch stopwatch;
HashRouter router(stopwatch, 2s);
HashRouter router(getSetup(2s, 1s), stopwatch);

uint256 const key1(1);
uint256 const key2(2);
Expand Down Expand Up @@ -174,7 +183,7 @@ class HashRouter_test : public beast::unit_test::suite
{
using namespace std::chrono_literals;
TestStopwatch stopwatch;
HashRouter router(stopwatch, 2s);
HashRouter router(getSetup(2s, 1s), stopwatch);

uint256 const key1(1);
BEAST_EXPECT(router.setFlags(key1, 10));
Expand All @@ -187,7 +196,7 @@ class HashRouter_test : public beast::unit_test::suite
{
using namespace std::chrono_literals;
TestStopwatch stopwatch;
HashRouter router(stopwatch, 1s);
HashRouter router(getSetup(50s, 1s), stopwatch);

uint256 const key1(1);

Expand Down Expand Up @@ -230,7 +239,7 @@ class HashRouter_test : public beast::unit_test::suite
{
using namespace std::chrono_literals;
TestStopwatch stopwatch;
HashRouter router(stopwatch, 5s);
HashRouter router(getSetup(5s, 1s), stopwatch);
uint256 const key(1);
HashRouter::PeerShortID peer = 1;
int flags;
Expand Down
5 changes: 5 additions & 0 deletions src/xrpld/app/ledger/LocalTxs.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ namespace ripple {
class LocalTxs
{
public:
// The number of ledgers to hold a transaction is essentially
// arbitrary. It should be sufficient to allow the transaction to
// get into a fully-validated ledger.
static constexpr int holdLedgers = 5;

virtual ~LocalTxs() = default;

// Add a new local transaction
Expand Down
28 changes: 10 additions & 18 deletions src/xrpld/app/ledger/detail/LedgerMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,25 +458,17 @@ LedgerMaster::storeLedger(std::shared_ptr<Ledger const> ledger)
void
LedgerMaster::applyHeldTransactions()
{
std::lock_guard sl(m_mutex);
CanonicalTXSet const set = [this]() {
std::lock_guard sl(m_mutex);
// VFALCO NOTE The hash for an open ledger is undefined so we use
// something that is a reasonable substitute.
CanonicalTXSet set(app_.openLedger().current()->info().parentHash);
std::swap(mHeldTransactions, set);
return set;
}();

app_.openLedger().modify([&](OpenView& view, beast::Journal j) {
bool any = false;
for (auto const& it : mHeldTransactions)
{
ApplyFlags flags = tapNONE;
auto const result =
app_.getTxQ().apply(app_, view, it.second, flags, j);
any |= result.applied;
}
return any;
});

// VFALCO TODO recreate the CanonicalTxSet object instead of resetting
// it.
// VFALCO NOTE The hash for an open ledger is undefined so we use
// something that is a reasonable substitute.
mHeldTransactions.reset(app_.openLedger().current()->info().parentHash);
if (!set.empty())
app_.getOPs().processTransactionSet(set);
}

std::shared_ptr<STTx const>
Expand Down
7 changes: 1 addition & 6 deletions src/xrpld/app/ledger/detail/LocalTxs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,9 @@ namespace ripple {
class LocalTx
{
public:
// The number of ledgers to hold a transaction is essentially
// arbitrary. It should be sufficient to allow the transaction to
// get into a fully-validated ledger.
static int const holdLedgers = 5;

LocalTx(LedgerIndex index, std::shared_ptr<STTx const> const& txn)
: m_txn(txn)
, m_expire(index + holdLedgers)
, m_expire(index + LocalTxs::holdLedgers)
, m_id(txn->getTransactionID())
, m_account(txn->getAccountID(sfAccount))
, m_seqProxy(txn->getSeqProxy())
Expand Down
4 changes: 2 additions & 2 deletions src/xrpld/app/main/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,8 @@ class ApplicationImp : public Application, public BasicApp
std::make_unique<LoadFeeTrack>(logs_->journal("LoadManager")))

, hashRouter_(std::make_unique<HashRouter>(
stopwatch(),
HashRouter::getDefaultHoldTime()))
setup_HashRouter(*config_),
stopwatch()))

, mValidations(
ValidationParms(),
Expand Down
2 changes: 2 additions & 0 deletions src/xrpld/app/main/Tuning.h
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add to this file

#include <chrono>

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ namespace ripple {
constexpr std::size_t fullBelowTargetSize = 524288;
constexpr std::chrono::seconds fullBelowExpiration = std::chrono::minutes{10};

constexpr std::size_t maxPoppedTransactions = 10;

} // namespace ripple

#endif
12 changes: 8 additions & 4 deletions src/xrpld/app/misc/CanonicalTXSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,22 @@ CanonicalTXSet::popAcctTransaction(std::shared_ptr<STTx const> const& tx)
// 1. Prioritize transactions with Sequences over transactions with
// Tickets.
//
// 2. Don't worry about consecutive Sequence numbers. Creating Tickets
// can introduce a discontinuity in Sequence numbers.
// 2. For transactions not using Tickets, look for consecutive Sequence
// numbers. For transactions using Tickets, don't worry about
// consecutive Sequence numbers. Tickets can process out of order.
//
// 3. After handling all transactions with Sequences, return Tickets
// with the lowest Ticket ID first.
std::shared_ptr<STTx const> result;
uint256 const effectiveAccount{accountKey(tx->getAccountID(sfAccount))};

Key const after(effectiveAccount, tx->getSeqProxy(), beast::zero);
auto const seqProxy = tx->getSeqProxy();
Key const after(effectiveAccount, seqProxy, beast::zero);
auto const itrNext{map_.lower_bound(after)};
if (itrNext != map_.end() &&
itrNext->first.getAccount() == effectiveAccount)
itrNext->first.getAccount() == effectiveAccount &&
(!itrNext->second->getSeqProxy().isSeq() ||
itrNext->second->getSeqProxy().value() == seqProxy.value() + 1))
{
result = std::move(itrNext->second);
map_.erase(itrNext);
Expand Down
41 changes: 39 additions & 2 deletions src/xrpld/app/misc/HashRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include <xrpld/app/misc/HashRouter.h>

#include <xrpld/core/Config.h>

namespace ripple {

auto
Expand All @@ -33,7 +35,7 @@
}

// See if any supressions need to be expired
expire(suppressionMap_, holdTime_);
expire(suppressionMap_, setup_.holdTime);

return std::make_pair(
std::ref(suppressionMap_.emplace(key, Entry()).first->second), true);
Expand Down Expand Up @@ -122,10 +124,45 @@

auto& s = emplace(key).first;

if (!s.shouldRelay(suppressionMap_.clock().now(), holdTime_))
if (!s.shouldRelay(suppressionMap_.clock().now(), setup_.relayTime))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a comment here why relayTime value is used for holdTime parameter ? Also, it appears to be the only use of the Entry::shouldRelay function, perhaps this parameter needs to be renamed to relayTime or retryTime ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a comment here why relayTime value is used for holdTime parameter ? Also, it appears to be the only use of the Entry::shouldRelay function, perhaps this parameter needs to be renamed to relayTime or retryTime ?

The parameter in s.shouldRelay is named holdTime because that's the value that was used before I introduced the shorter relay retry cutoff. I'll rename it.

return {};

return s.releasePeerSet();
}

HashRouter::Setup
setup_HashRouter(Config const& config)
{
using namespace std::chrono;

HashRouter::Setup setup;
auto const& section = config.section("hashrouter");

std::int32_t tmp;

if (set(tmp, "hold_time", section))
{
if (tmp < 8)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message below says something different; is this meant to be 8 or 12 ?

Also, given this is a free function, it should be easy to add to unit tests, including test that an exception is thrown.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message below says something different; is this meant to be 8 or 12 ?

This looks like a copy/paste error. Unfortunately, I don't remember which direction. LOL.

Throw<std::runtime_error>(

Check warning on line 146 in src/xrpld/app/misc/HashRouter.cpp

View check run for this annotation

Codecov / codecov/patch

src/xrpld/app/misc/HashRouter.cpp#L146

Added line #L146 was not covered by tests
"HashRouter hold time must be at least 12 seconds (the "
"approximate validation time for three ledgers).");
setup.holdTime = seconds(tmp);

Check warning on line 149 in src/xrpld/app/misc/HashRouter.cpp

View check run for this annotation

Codecov / codecov/patch

src/xrpld/app/misc/HashRouter.cpp#L149

Added line #L149 was not covered by tests
}
if (set(tmp, "relay_time", section))
{
if (tmp < 8)
Throw<std::runtime_error>(

Check warning on line 154 in src/xrpld/app/misc/HashRouter.cpp

View check run for this annotation

Codecov / codecov/patch

src/xrpld/app/misc/HashRouter.cpp#L154

Added line #L154 was not covered by tests
"HashRouter relay time must be at least 8 seconds (the "
"approximate validation time for two ledgers).");
setup.relayTime = seconds(tmp);

Check warning on line 157 in src/xrpld/app/misc/HashRouter.cpp

View check run for this annotation

Codecov / codecov/patch

src/xrpld/app/misc/HashRouter.cpp#L157

Added line #L157 was not covered by tests
}
if (setup.relayTime > setup.holdTime)
{
Throw<std::runtime_error>(

Check warning on line 161 in src/xrpld/app/misc/HashRouter.cpp

View check run for this annotation

Codecov / codecov/patch

src/xrpld/app/misc/HashRouter.cpp#L161

Added line #L161 was not covered by tests
"HashRouter relay time must be less than or equal to hold time");
}

return setup;
}

} // namespace ripple
48 changes: 34 additions & 14 deletions src/xrpld/app/misc/HashRouter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace ripple {
// TODO convert these macros to int constants or an enum
#define SF_BAD 0x02 // Temporarily bad
#define SF_SAVED 0x04
#define SF_HELD 0x08 // Held by LedgerMaster after potential processing failure
#define SF_TRUSTED 0x10 // comes from trusted source

// Private flags, used internally in apply.cpp.
Expand All @@ -44,6 +45,8 @@ namespace ripple {
#define SF_PRIVATE5 0x1000
#define SF_PRIVATE6 0x2000

class Config;

/** Routing table for objects identified by hash.

This table keeps track of which hashes have been received by which peers.
Expand All @@ -56,6 +59,27 @@ class HashRouter
// The type here *MUST* match the type of Peer::id_t
using PeerShortID = std::uint32_t;

/** Structure used to customize @ref HashRouter behavior.
*
* Even though these items are configurable, don't change them unless there
* is a good reason, and network-wide coordination to do it.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. On the one hand, this comment and the code implies that we should best rely on hardcoded values, on the other it is read from configuration, but the new configuration values are not documented in cfg/rippled-example.cfg.

Perhaps it would be better to 1. remove default constructor 2. remove default values from members and move them to setup_HashRouter, adding comment here about where the default values are 3. make the data members const and 4. add hashrouter section and appropriate documentation to cfg/rippled-example.cfg

I do not insist this is better but it will be probably easier to understand what's going on : better cohesion re. parsing configuration and populating this structure, immutable data members, documented config in cfg/rippled-example.cfg

Alternatively (perhaps even better), keep the default values here, give up on reading this from configuration and remove setup_HashRouter altogether. If network-wide action is needed to update these values, such action could be in principle "deploy new binary" rather than "agree with everyone to change the configuration", where deploying new binary has the added benefit that, in principle, everyone can see which validator is running which binary version.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty common pattern throughout rippled. For example FeeSetup and setup_FeeVote. The difference is that FeeSetup is documented. It's done this way with default values so that the structures can be used in, for example, unit tests using either the default values, or custom values without needing the overhead of having to populate a Config object. It's also handy to be able to look in one place to see what the defaults are. Most of the objects that use this pattern are singletons that are created on startup, so it's not like anybody is going to forget to call the setup_ function.

This isn't the only undocumented configuration feature in rippled. Those exist intentionally, because in some situations, it can be a lot faster to communicate with operators (especially UNL operators) and get them to update their config than it would be to roll out a new version, even if it's a hotfix.

Based on your feedback, I did update this comment to reflect

  1. The fact that it's undocumented.
  2. That setup_HashRouter processes the config.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, that works

*/
struct Setup
{
/// Default constructor
explicit Setup() = default;

using seconds = std::chrono::seconds;

/** Expiration time for a hash entry
*/
seconds holdTime{300};

/** Amount of time required before a relayed item will be relayed again.
*/
seconds relayTime{30};
};

private:
/** An entry in the routing table.
*/
Expand Down Expand Up @@ -135,16 +159,8 @@ class HashRouter
};

public:
static inline std::chrono::seconds
getDefaultHoldTime()
{
using namespace std::chrono;

return 300s;
}

HashRouter(Stopwatch& clock, std::chrono::seconds entryHoldTimeInSeconds)
: suppressionMap_(clock), holdTime_(entryHoldTimeInSeconds)
HashRouter(Setup const& setup, Stopwatch& clock)
: setup_(setup), suppressionMap_(clock)
{
}

Expand Down Expand Up @@ -195,11 +211,11 @@ class HashRouter
Effects:

If the item should be relayed, this function will not
return `true` again until the hold time has expired.
return a seated optional again until the relay time has expired.
The internal set of peers will also be reset.

@return A `std::optional` set of peers which do not need to be
relayed to. If the result is uninitialized, the item should
relayed to. If the result is unseated, the item should
_not_ be relayed.
*/
std::optional<std::set<PeerShortID>>
Expand All @@ -212,17 +228,21 @@ class HashRouter

std::mutex mutable mutex_;

// Configurable parameters
Setup const setup_;

// Stores all suppressed hashes and their expiration time
beast::aged_unordered_map<
uint256,
Entry,
Stopwatch::clock_type,
hardened_hash<strong_hash>>
suppressionMap_;

std::chrono::seconds const holdTime_;
};

HashRouter::Setup
setup_HashRouter(Config const&);

} // namespace ripple

#endif
Loading
Loading