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

Enforce account RPC limits by account objects traversed #4032

Closed
wants to merge 25 commits into from

Conversation

natenichols
Copy link
Contributor

High Level Overview of Change

Modifies account RPCs to enforce limits by number of account objects traversed.

Context of Change

Previously, we limited account RPCs by the number of objects returned, not the number of objects traversed. This can get expensive when traversing accounts with a lot of owned objects. This PR modifies this behavior to enforce limits based on number of objects traversed. It also slightly changes how we do markers, including the marker startHint in the marker, similar to how account_objects works.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Release

Test Plan

If helpful, please describe the tests that you ran to verify your changes and provide instructions so that others can reproduce.
This section may not be needed if your change includes thoroughly commented unit tests.

Some tests had to be modified, including increasing limits and changing markers.

@natenichols natenichols self-assigned this Dec 14, 2021
@ximinez ximinez self-requested a review December 14, 2021 21:57
@ximinez ximinez self-assigned this Dec 14, 2021
@scottschurr scottschurr self-requested a review December 14, 2021 23:15
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.

Looking at these three handlers together, I realize there's a ton of overlapping / boilerplate code that could probably be pulled into one or more common helper functions. That may be beyond the scope of this PR, but it would be pretty cool.

Otherwise, all of my feedback items are minor - comments, variable names, and such.

src/ripple/rpc/handlers/AccountChannels.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountChannels.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountChannels.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountChannels.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountLines.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountOffers.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountOffers.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountOffers.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountOffers.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/impl/RPCHelpers.h Outdated Show resolved Hide resolved
RichardAH and others added 15 commits December 14, 2021 17:43
This flag, if present, suppresses the output of incoming
trustlines in default state.

This is primarily motivated by observing that users of Xumm often
have many unwanted incoming trustlines in a default state, which are
not useful in the vast majority of cases.

Being able to suppress those when doing `account_lines` saves bandwidth
and resources.
* Just the rep is made atomic to workaround older compilers
seperated -> separated
determing -> determining
* Log load fee values (at debug) received from validations.
* Log remote and cluster fee values (at trace) when changed.
* Refactor JobQueue::isOverloaded to return sooner if overloaded.
* Refactor Transactor::checkFee to only compute fee if ledger is open.
* Sort by fee level (which is the current behavior) then by transaction
  ID (hash).
* Edge case when the account at the end of the queue submits a higher
  paying transaction to walk backwards and compare against the cheapest
  transaction from a different account.
* Use std::if_any to simplify the JobQueue::isOverloaded loop.
Copy link
Collaborator

@scottschurr scottschurr left a comment

Choose a reason for hiding this comment

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

I've finished my review and I'm okay with what's here. I'd be a lot more comfortable if we check isFieldPresent in getStartHint(). So I hope you'll look at the suggestions and see what you think. But, I'll acknowledge, there's also risk in changing stuff that's been well tested.

@natenichols natenichols requested a review from ximinez December 15, 2021 15:40
src/ripple/rpc/handlers/AccountChannels.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountLines.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/handlers/AccountOffers.cpp Outdated Show resolved Hide resolved
src/ripple/rpc/impl/RPCHelpers.cpp Show resolved Hide resolved
src/test/rpc/AccountLinesRPC_test.cpp Outdated Show resolved Hide resolved
@cjcobb23
Copy link
Contributor

Just want to point out this change actually changes the behavior of the RPCs from a client perspective. The call will return less objects than what is specified in limit. It could even return no objects, but a marker, in which case a user should continue paging. None of this is actually API breaking, as the server is not required to honor the limit. I think these changes are appropriate and beneficial, but just wanted to make sure everyone is aware. @mDuo13 chime in if you object to these changes.

@natenichols
Copy link
Contributor Author

natenichols commented Dec 15, 2021

@cjcobb23, I'm okay to wait on this PR until 1.8.3, its already running in reporting mode, which is where it is most important.

If we don't feel comfortable shipping it right now, we can wait until the next release. Thoughts?

@cjcobb23
Copy link
Contributor

@natenichols I would like to ship it now, because we are trying to make it easy for others to run reporting mode. I think this will also benefit regular rippled.

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.

👍 I think this is appropriate for 1.8.2, FWIW.

@natenichols natenichols added the Passed Passed code review & PR owner thinks it's ready to merge. Perf sign-off may still be required. label Dec 15, 2021
@scottschurr
Copy link
Collaborator

@natenichols, the latest changes look good to me.

Thanks for adding the unit test, however I don't think it is testing as much as you hope for. When I check code coverage I see that, even with the added test, none of the non-manual unit tests exercise the ltSIGNER_LIST branch of isOwnedByAccount().

I'll poke at a way to fix the new unit test so it exercises that branch. But in the mean time, know that we haven't verified that part of the code.

Copy link
Collaborator

@mDuo13 mDuo13 left a comment

Choose a reason for hiding this comment

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

At a glance this looks fine, though it's a bit hard for me to figure out all the consequences this might have on the API.

Are the markers portable across servers, or not? Say you connect via JSON-RPC to a hostname that is backed by a round-robin pool of servers. If you do a request and get a marker back, but then your follow-up request using the marker goes to a different machine, will pagination continue smoothly? Ideally I think all markers should be portable across machines, but that's not a guarantee we provide for all calls. (The account_tx command does guarantee portability of its markers, but that's a different story.)

@@ -46,7 +46,7 @@ static LimitRange constexpr accountObjects = {10, 200, 400};
static LimitRange constexpr accountOffers = {10, 200, 400};

/** Limits for the book_offers command. */
static LimitRange constexpr bookOffers = {0, 300, 400};
static LimitRange constexpr bookOffers = {0, 60, 100};
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if you specify a limit=200 for example? To my understanding, that would have been allowed in the old API but it's too large in the new API. Depending on the behavior, this may or may not be a breaking change that requires clients to be rewritten:

  • If the limit is quietly clamped to the new max limit of 100, that's OK. Clients already need to assume that the API may return fewer than their specified limit.
  • If the command now returns an error like rpcINVALID_PARAMS, that's a problematic breaking change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Limits are quietly clamped.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These limits also are only applied to non-admin clients

@natenichols
Copy link
Contributor Author

natenichols commented Dec 15, 2021

Are the markers portable across servers, or not?

No, they are not portable across servers. There is not a scenario where these changes could make markers portable, since now markers can be the index of a non-RippleState SLE, which is not allowed pre 1.8.2.

If you do a request and get a marker back, but then your follow-up request using the marker goes to a different machine, will pagination continue smoothly?

Yes, as long as all servers in the same cluster are running 1.8.2. If there are different versions of rippled running in the same cluster, then no, because markers are not portable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Passed Passed code review & PR owner thinks it's ready to merge. Perf sign-off may still be required.
Projects
None yet
Development

Successfully merging this pull request may close these issues.