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

Proposed version 2.3.1 #5243

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

vlntb
Copy link
Collaborator

@vlntb vlntb commented Jan 13, 2025

High Level Overview of Change

This is a hotfix release that fixes an erroneous high fee penalty that peers can be charged for sending older transactions.

Context of Change

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Release

API Impact

  • Public API: New feature (new methods and/or new fields)
  • Public API: Breaking change (in general, breaking changes should only impact the next api_version)
  • libxrpl change (any change that may affect libxrpl or dependents of libxrpl)
  • Peer protocol change (must be backward compatible or bump the peer protocol version)

Copy link

codecov bot commented Jan 13, 2025

Codecov Report

Attention: Patch coverage is 24.02597% with 117 lines in your changes missing coverage. Please review.

Project coverage is 77.8%. Comparing base (f64cf91) to head (d7a8a26).

Files with missing lines Patch % Lines
src/xrpld/overlay/detail/PeerImp.cpp 1.0% 98 Missing ⚠️
src/xrpld/app/ledger/detail/InboundLedger.cpp 0.0% 5 Missing ⚠️
...rc/xrpld/app/ledger/detail/InboundTransactions.cpp 0.0% 4 Missing ⚠️
src/xrpld/app/ledger/detail/LedgerMaster.cpp 0.0% 4 Missing ⚠️
src/xrpld/overlay/detail/PeerImp.h 0.0% 4 Missing ⚠️
include/xrpl/resource/detail/Logic.h 93.3% 1 Missing ⚠️
src/xrpld/overlay/detail/OverlayImpl.cpp 95.2% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           master   #5243     +/-   ##
========================================
- Coverage    77.9%   77.8%   -0.1%     
========================================
  Files         784     784             
  Lines       66681   66734     +53     
  Branches     8162    8198     +36     
========================================
- Hits        51950   51938     -12     
- Misses      14731   14796     +65     
Files with missing lines Coverage Δ
src/libxrpl/protocol/BuildInfo.cpp 98.2% <ø> (ø)
src/libxrpl/resource/Consumer.cpp 89.8% <100.0%> (ø)
src/xrpld/overlay/Overlay.h 70.0% <ø> (ø)
src/xrpld/overlay/Peer.h 100.0% <ø> (ø)
src/xrpld/overlay/detail/OverlayImpl.h 40.0% <ø> (ø)
include/xrpl/resource/detail/Logic.h 57.0% <93.3%> (+1.8%) ⬆️
src/xrpld/overlay/detail/OverlayImpl.cpp 35.7% <95.2%> (+1.0%) ⬆️
...rc/xrpld/app/ledger/detail/InboundTransactions.cpp 52.6% <0.0%> (ø)
src/xrpld/app/ledger/detail/LedgerMaster.cpp 43.9% <0.0%> (ø)
src/xrpld/overlay/detail/PeerImp.h 13.2% <0.0%> (-0.4%) ⬇️
... and 2 more

... and 6 files with indirect coverage changes

Impacted file tree graph

@vlntb vlntb changed the title fix fee from feeInvalidSignature to feeUnwantedData Proposed version 2.3.1 Jan 14, 2025
@vlntb vlntb requested a review from ximinez January 14, 2025 12:59
@vlntb vlntb marked this pull request as ready for review January 14, 2025 13:00
* Before: Pseudo-transactions received from a peer will fail the signature
  check, even if they were requested (using TMGetObjectByHash), because
  they have no signature. This causes the peer to be charge for an
  invalid signature.
* After: Pseudo-transactions, are put into the global cache
  (TransactionMaster) only. If the transaction is part of
  a TMTransactions batch, the peer is charged the equivalent of one
  trivial request per transaction. If not, the peer is charged an
  unwanted data fee. These fees will not be a problem in the normal
  course of operations, but should dissuade peers from behaving badly by
  sending a bunch of junk.
* If reduce relay is enabled, it will queue up the tx id for peers that
  also have it enabled so they can ask for it later if they need it.
Copy link
Collaborator

@ximinez ximinez left a comment

Choose a reason for hiding this comment

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

Go ahead and squash the last two commits (version and release notes) into one, and change the commit message to follow the standard format: "Set version to 2.3.1"

@vlntb vlntb marked this pull request as draft January 16, 2025 18:19
Comment on lines 226 to 253
auto const kp1 = randomKeyPair(KeyType::secp256k1);
auto const id1 = calcAccountID(kp1.first);

auto const kp2 = randomKeyPair(KeyType::secp256k1);
auto const id2 = calcAccountID(kp2.first);

auto getPayment = [kp1, id1, id2]() {
// Account id1 pays account id2 10,000 XRP.
STObject payment(sfGeneric);
payment.setFieldU16(sfTransactionType, ttPAYMENT);
payment.setAccountID(sfAccount, id1);
payment.setAccountID(sfDestination, id2);
payment.setFieldAmount(sfAmount, STAmount(10000000000ull));
payment.setFieldAmount(sfFee, STAmount(10ull));
payment.setFieldU32(sfSequence, 1);
payment.setFieldVL(
sfSigningPubKey, Slice(kp1.first.data(), kp1.first.size()));
return payment;
};
auto stx = STTx{getPayment()};

protocol::TMTransaction m;
m.set_rawtransaction("transaction");
Serializer s;
stx.add(s);
m.set_rawtransaction(s.data(), s.size());
m.set_deferred(false);
m.set_status(protocol::TransactionStatus::tsNEW);
env.app().overlay().relay(uint256{0}, m, toSkip);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Building the transaction like this is overkill. Can I suggest:

        auto const jtx = env.jt(noop(env.master));
        if (BEAST_EXPECT(jtx.stx))
        {
            protocol::TMTransaction m;
            Serializer s;

            jtx.stx->add(s);
            m.set_rawtransaction(s.data(), s.size());
            m.set_deferred(false);
            m.set_status(protocol::TransactionStatus::tsNEW);
            env.app().overlay().relay(uint256{0}, m, toSkip);
            BEAST_EXPECT(
                PeerTest::sendTx_ == expectRelay &&
                PeerTest::queueTx_ == expectQueue);
        }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thank you for pointing this out. I copied what other unit-tests are doing. But using env.jt is a lot more compact.

@@ -6,6 +6,55 @@ This document contains the release notes for `rippled`, the reference server imp

Have new ideas? Need help with setting up your node? [Please open an issue here](https://github.com/xrplf/rippled/issues/new/choose).

# Version 2.3.1

Version 2.3.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes an erroneous high fee penalty that peers can be charged for sending older transactions.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will probably need to be rephrased in light of the additional changes made.

include/xrpl/resource/detail/Logic.h Outdated Show resolved Hide resolved
src/xrpld/overlay/detail/OverlayImpl.cpp Outdated Show resolved Hide resolved
@ximinez ximinez mentioned this pull request Jan 23, 2025
5 tasks
Comment on lines +447 to +450
assert(
feeDrop.cost() > feeInvalidSignature.cost() &&
feeInvalidSignature.cost() > feeInvalidRequest.cost() &&
feeInvalidRequest.cost() > 10);
Copy link
Collaborator

Choose a reason for hiding this comment

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

As these fees are const, can you move these to a static initializer that's guaranteed to only be called once? Or otherwise something that isn't called as frequently, like a constructor?

I chatted with Ed and he suggested possibly make_Manager in ResourceManager.cpp? It's called from the Application ctor.

@@ -22,11 +22,11 @@
namespace ripple {
namespace Resource {

Charge const feeInvalidRequest(100, "malformed request");
Charge const feeInvalidRequest(200, "malformed request");
Copy link
Collaborator

Choose a reason for hiding this comment

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

For some of the variables here and below, the name and description are inconsistent.

  • invalid request vs. malformed request => invalid is more general while malformed is more specific.
  • request no reply vs unsatisfiable request => no reply is more specific while unsatisfiable is more general.
  • unwanted vs. useless => similar, but different. unwanted data can still be useful, just not wanted right now.
  • etc.

Can you rename the variables or modify the descriptions to improve consistency?

Copy link
Collaborator

Choose a reason for hiding this comment

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

IMHO, changing the variable names would be better because the descriptions are used in log messages, which, while not a fixed API or anything, are more visible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That was my worry, too - we are relying on the logs a lot, and we need to be sure that we are not breaking someone's dashboard if we change the message in the area that hasn't been updated for a while. If we all agree, I'll be happy to update the variable names.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Updating the variable names sounds good.

src/xrpld/overlay/detail/PeerImp.h Outdated Show resolved Hide resolved
void
append(Resource::Charge f, std::string const& add)
{
fee = f;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rather than overwriting the fee, why not first check if the fee is higher or lower, and only overwrite if it is higher?

Alternatively, Ed suggested just adding a assert(newFee >= oldFee); as the updated fee should not be lower.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree with assert(newFee >= oldFee); proposal. We don't want to do these checks always if this condition is impossible. Once we confirm it with assert assistance in debug builds, it makes sense to skip this comparison in the release for performance reasons.

append(Resource::Charge f, std::string const& add)
{
fee = f;
context += add;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I noticed that the calls to charge sometimes have the string with a space in front (e.g. string) and sometimes not (string). The latter ones currently will be concatenated as is, without separation.

Better would be:

  1. Update all add arguments passed in calls to this function to not have the leading space.
  2. Here, check if context is empty, and if not add a space before adding the passed in string.

Copy link
Collaborator

@bthomee bthomee left a comment

Choose a reason for hiding this comment

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

There are a couple of discrepancies when updating the fee for received messages, whereby a mixture of calls to fee_.update and charge happen in the OnMessage.

The first comment provides more details. I only highlighted the charge calls that should be changed to fee_.update. There may be other calls in existing code that GitHub didn't show me, but which then also need to be modified. All this can be done in a follow-up PR, but it's so simple you may as well include it now.

@@ -1173,7 +1173,7 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMEndpoints> const& m)
// implication for the protocol.
if (m->endpoints_v2().size() >= 1024)
{
charge(Resource::feeBadData);
charge(Resource::feeBadData, "endpoints too large");
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the function is a message handler (onMessage) or called directly from a message handler, it should use fee_, since then the handler returns (OnMessageEnd) the charge function is called.

If the function is not a message handler, such as a job queue item, it should be charge.

So in this location, the charge should not be here, and presumably should use fee_.

@@ -1188,7 +1188,7 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMEndpoints> const& m)
{
JLOG(p_journal_.error()) << "failed to parse incoming endpoint: {"
<< tm.endpoint() << "}";
charge(Resource::feeBadData);
charge(Resource::feeBadData, "endpoints malformed");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

@@ -1318,7 +1325,7 @@ void
PeerImp::onMessage(std::shared_ptr<protocol::TMGetLedger> const& m)
{
auto badData = [&](std::string const& msg) {
charge(Resource::feeBadData);
charge(Resource::feeBadData, "get_ledger " + msg);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

@@ -1409,11 +1416,12 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMProofPathRequest> const& m)
JLOG(p_journal_.trace()) << "onMessage, TMProofPathRequest";
if (!ledgerReplayEnabled_)
{
charge(Resource::feeInvalidRequest);
charge(Resource::feeInvalidRequest, "proof_path_request disabled");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

@@ -1458,11 +1468,11 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMReplayDeltaRequest> const& m)
JLOG(p_journal_.trace()) << "onMessage, TMReplayDeltaRequest";
if (!ledgerReplayEnabled_)
{
charge(Resource::feeInvalidRequest);
charge(Resource::feeInvalidRequest, "replay_delta_request disabled");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

return;
}

if (!ledgerReplayMsgHandler_.processReplayDeltaResponse(m))
{
charge(Resource::feeBadData);
charge(Resource::feeBadData, "replay_delta_response");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

@@ -2572,22 +2600,22 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMSquelch> const& m)

if (!m->has_validatorpubkey())
{
charge(Resource::feeBadData);
charge(Resource::feeBadData, "squelch no pubkey");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

return;
}
auto validator = m->validatorpubkey();
auto const slice{makeSlice(validator)};
if (!publicKeyType(slice))
{
charge(Resource::feeBadData);
charge(Resource::feeBadData, "squelch bad pubkey");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

return;
}
PublicKey key(slice);

// Ignore non-validator squelch
if (!app_.validators().listed(key))
{
charge(Resource::feeBadData);
charge(Resource::feeBadData, "squelch non-validator");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

@@ -2607,7 +2635,7 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMSquelch> const& m)
if (!m->squelch())
squelch_.removeSquelch(key);
else if (!squelch_.addSquelch(key, std::chrono::seconds{duration}))
charge(Resource::feeBadData);
charge(Resource::feeBadData, "squelch duration");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, regarding fee_ vs charge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants