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 all 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
134 changes: 128 additions & 6 deletions src/test/app/HashRouter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//==============================================================================

#include <xrpld/app/misc/HashRouter.h>
#include <xrpld/core/Config.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/unit_test.h>

Expand All @@ -26,12 +27,22 @@ 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()
{
testcase("Non-expiration");
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 @@ -66,9 +77,10 @@ class HashRouter_test : public beast::unit_test::suite
void
testExpiration()
{
testcase("Expiration");
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 @@ -143,10 +155,11 @@ class HashRouter_test : public beast::unit_test::suite
void
testSuppression()
{
testcase("Suppression");
// 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 All @@ -172,9 +185,10 @@ class HashRouter_test : public beast::unit_test::suite
void
testSetFlags()
{
testcase("Set Flags");
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 @@ -185,9 +199,10 @@ class HashRouter_test : public beast::unit_test::suite
void
testRelay()
{
testcase("Relay");
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 @@ -228,9 +243,10 @@ class HashRouter_test : public beast::unit_test::suite
void
testProcess()
{
testcase("Process");
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 All @@ -242,6 +258,111 @@ class HashRouter_test : public beast::unit_test::suite
BEAST_EXPECT(router.shouldProcess(key, peer, flags, 1s));
}

void
testSetup()
{
testcase("setup_HashRouter");

using namespace std::chrono_literals;
{
Config cfg;
// default
auto const setup = setup_HashRouter(cfg);
BEAST_EXPECT(setup.holdTime == 300s);
BEAST_EXPECT(setup.relayTime == 30s);
}
{
Config cfg;
// non-default
auto& h = cfg.section("hashrouter");
h.set("hold_time", "600");
h.set("relay_time", "15");
auto const setup = setup_HashRouter(cfg);
BEAST_EXPECT(setup.holdTime == 600s);
BEAST_EXPECT(setup.relayTime == 15s);
}
{
Config cfg;
// equal
auto& h = cfg.section("hashrouter");
h.set("hold_time", "400");
h.set("relay_time", "400");
auto const setup = setup_HashRouter(cfg);
BEAST_EXPECT(setup.holdTime == 400s);
BEAST_EXPECT(setup.relayTime == 400s);
}
{
Config cfg;
// wrong order
auto& h = cfg.section("hashrouter");
h.set("hold_time", "60");
h.set("relay_time", "120");
try
{
setup_HashRouter(cfg);
fail();
}
catch (std::exception const& e)
{
std::string expected =
"HashRouter relay time must be less than or equal to hold "
"time";
BEAST_EXPECT(e.what() == expected);
}
}
{
Config cfg;
// too small hold
auto& h = cfg.section("hashrouter");
h.set("hold_time", "10");
h.set("relay_time", "120");
try
{
setup_HashRouter(cfg);
fail();
}
catch (std::exception const& e)
{
std::string expected =
"HashRouter hold time must be at least 12 seconds (the "
"approximate validation time for three "
"ledgers).";
BEAST_EXPECT(e.what() == expected);
}
}
{
Config cfg;
// too small relay
auto& h = cfg.section("hashrouter");
h.set("hold_time", "500");
h.set("relay_time", "6");
try
{
setup_HashRouter(cfg);
fail();
}
catch (std::exception const& e)
{
std::string expected =
"HashRouter relay time must be at least 8 seconds (the "
"approximate validation time for two ledgers).";
BEAST_EXPECT(e.what() == expected);
}
}
{
Config cfg;
// garbage
auto& h = cfg.section("hashrouter");
h.set("hold_time", "alice");
h.set("relay_time", "bob");
auto const setup = setup_HashRouter(cfg);
// The set function ignores values that don't covert, so the
// defaults are left unchanged
BEAST_EXPECT(setup.holdTime == 300s);
BEAST_EXPECT(setup.relayTime == 30s);
}
}

public:
void
run() override
Expand All @@ -252,6 +373,7 @@ class HashRouter_test : public beast::unit_test::suite
testSetFlags();
testRelay();
testProcess();
testSetup();
}
};

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 @@ -34,6 +34,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 @@ -52,14 +52,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 @@ -440,8 +440,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
4 changes: 4 additions & 0 deletions src/xrpld/app/main/Tuning.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
#ifndef RIPPLE_APP_MAIN_TUNING_H_INCLUDED
#define RIPPLE_APP_MAIN_TUNING_H_INCLUDED

#include <chrono>

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 @@ HashRouter::emplace(uint256 const& key) -> std::pair<Entry&, bool>
}

// 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 @@ HashRouter::shouldRelay(uint256 const& key)

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 < 12)
Throw<std::runtime_error>(
"HashRouter hold time must be at least 12 seconds (the "
"approximate validation time for three ledgers).");
setup.holdTime = seconds(tmp);
}
if (set(tmp, "relay_time", section))
{
if (tmp < 8)
Throw<std::runtime_error>(
"HashRouter relay time must be at least 8 seconds (the "
"approximate validation time for two ledgers).");
setup.relayTime = seconds(tmp);
}
if (setup.relayTime > setup.holdTime)
{
Throw<std::runtime_error>(
"HashRouter relay time must be less than or equal to hold time");
}

return setup;
}

} // namespace ripple
Loading
Loading