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

RPC commands understand markers derived from all ledger object types #4361

Merged
merged 18 commits into from
Mar 20, 2023

Conversation

ximinez
Copy link
Collaborator

@ximinez ximinez commented Dec 2, 2022

High Level Overview of Change

Users are encountering situations where markers returned by the account_lines command don't work on subsequent commands, returning "Invalid Parameters".

Resolves #4340 and #4354

Context of Change

This issue derives from the optimization implemented in Enforce account RPC limits by account objects traversed. Previously, the ledger traversal would find up to limit account lines, and if there were more, the marker would be derived from the key of the next account line. After the change, ledger traversal would consider up to limit account objects of any kind found in the account's directory structure. If there were more, the marker would be derived from the key of the next object, regardless of type.

Note that because of this optimization it is expected that account_lines may return fewer than limit account lines, even 0, along with a marker indicating there are more available.

The problem is that this optimization did not update the RPC::isOwnedByAccount helper function to handle those other object types. Additionally, the XLS20d implementation added ltNFTOKEN_OFFER ledger objects to objects that have been added to the account's directory structure, but did not update RPC::isOwnedByAccount to be able to handle those objects. The marker provided in the example for #4354 includes the key for an ltNFTOKEN_OFFER. When that marker is used on subsequent calls, it is not recognized as valid, and so the request fails.

Type of Change

  • [X ] Bug fix (non-breaking change which fixes an issue)
  • [X ] Tests (You added tests for code that already exists, or your new feature included in this PR)

Test Plan

Reproduce the situation described in #4354. It may be necessary to specify ledger_index 75211418, because ledger state may change. With the old code, the second request, using the marker will fail. With the new code, it will succeed.

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.

The fix looks right, and I love the test. I left a note where I think some kind of comment is needed, but other than that I think this is good to go. Thanks for characterizing and fixing this problem.

src/ripple/rpc/impl/RPCHelpers.cpp Show resolved Hide resolved
Comment on lines +548 to +561
auto escrow = [&env](
Account const& account,
Account const& to,
STAmount const& amount) {
Json::Value jv;
jv[jss::TransactionType] = jss::EscrowCreate;
jv[jss::Flags] = tfUniversal;
jv[jss::Account] = account.human();
jv[jss::Destination] = to.human();
jv[jss::Amount] = amount.getJson(JsonOptions::none);
NetClock::time_point finish = env.now() + 1s;
jv[sfFinishAfter.jsonName] = finish.time_since_epoch().count();
return jv;
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm noticing that there are functions or manual code to create escrows scattered around the test subdirectory. I see them in...

  • Escrow_test.cpp,
  • AccountDelete_test.cpp,
  • LedgerRPC_test.cpp,
  • AccountObjects_test.cpp,
  • AccountTx_test.cpp, and
  • LedgerData_test.cpp

It's probably time we bit the bullet and wrote some common code to build escrows in the test environment. But I don't need to burden this pull request with that change. Just an observation.

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. I actually stole my code from Escrow_test.cpp, I think.

Copy link
Collaborator

@dangell7 dangell7 Feb 3, 2023

Choose a reason for hiding this comment

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

I can attempt to apply the solve in this PR if you let me know what you want.

#4396

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hi @dangell7, thanks for the offer. I can't give you a precise definition of what I'm looking for, but here's a hand wave.

First, note that there are several different unit test files that locally define functions or lambdas which

  1. Create escrows,
  2. Finish escrows, or
  3. Cancel escrows.

Here's where those functions are defined (locally) in Escrow_test.cpp: https:/XRPLF/rippled/blob/develop/src/test/app/Escrow_test.cpp#L170-L190

Since this functions are only defined locally, they are not available to all of the test files that need to do these escrow operations. So the functions have been copied, pasted, and mutated into different test files. The escrow lambda, on line 548 here in this file, is one such example.

However, if we pulled those functions out of Escrow_test.cpp and put them somewhere they could be used by all the tests, then we can remove a lot of code duplication.

An example you could consider following is the src/test/jtx/check.h and src/test/jtx/impl/check.cpp files. Those files create a check namespace and put all of the check-related functions in there. So in tests the functions are invoked like check::create(...) or check::cash(...). That seems like a pretty good approach for less common facilities like checks and escrows.

But once you've made those functions in the escrow namespace the work has only started. Now you need to go through all of the tests that use escrows and remove all of those local functions and lambdas. Replace calls to those local functions will calls to the new functions you created in the escrow namespace. This may get tricky, because the escrow-related functions that have been copied around may have mutated. So the interfaces of the copied functions may not be uniform across the code base.

Once you've...

  1. Created the new globally accessible test functions,
  2. Removed all of the local definitions,
  3. Replaced calls to those local definitions with calls to the new global functions, and
  4. The unit tests all pass.

Then you're done.

Does that make sense? It may be more work than you want to take on in your pull request. It may make more sense as a separate pull request.

Comment on lines +563 to +577
auto payChan = [](Account const& account,
Account const& to,
STAmount const& amount,
NetClock::duration const& settleDelay,
PublicKey const& pk) {
Json::Value jv;
jv[jss::TransactionType] = jss::PaymentChannelCreate;
jv[jss::Flags] = tfUniversal;
jv[jss::Account] = account.human();
jv[jss::Destination] = to.human();
jv[jss::Amount] = amount.getJson(JsonOptions::none);
jv["SettleDelay"] = settleDelay.count();
jv["PublicKey"] = strHex(pk.slice());
return jv;
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

The note for escrows, above, applies to payChans as well. They could both be addressed in the same pull request, but not necessarily this pull request.

Copy link
Collaborator

@dangell7 dangell7 Feb 3, 2023

Choose a reason for hiding this comment

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

I can attempt to apply the solve in this PR if you let me know what you want.

#4396

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hi @dangell7. Thanks for this offer also. The notes here https:/XRPLF/rippled/pull/4361/files#r1109064286 describe what would be done for escrows. An almost identical process could be followed for PayChan. You can think about whether that's a task you would like to take on.

src/test/rpc/AccountLinesRPC_test.cpp Outdated Show resolved Hide resolved
src/test/rpc/AccountLinesRPC_test.cpp Show resolved Hide resolved
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.

Looks great! Thanks for the comments and expanded test.

src/ripple/rpc/impl/RPCHelpers.cpp Show resolved Hide resolved
* Resolves XRPLF#4340 and XRPLF#4354
* Add unit test that walks all the object types and verifies that all of
  their indexes can work as a marker.
* Add more NFTokenOffer object test cases
* Add comments explaining the method for checking sfDestination
* upstream/develop:
  Add a unit test for invalid memos (XRPLF#4287)
* upstream/develop:
  Make NodeToShardRPC a manual test (XRPLF#4379)
  Update build instructions (XRPLF#4376)
@intelliot intelliot added this to the 1.10.1 milestone Feb 8, 2023
* upstream/develop:
  Update dependency: grpc (XRPLF#4407)
  Introduce min/max observers for Number
  Optimize uint128_t division by 10 within Number.cpp
  Replace Number division algorithm
  Include rounding mode in XRPAmount to STAmount conversion.
  Remove undefined behavior * Taking the negative of a signed negative is UB, but   taking the negative of an unsigned is not.
  Silence warnings
  Introduce rounding modes for Number:
  Use Number for IOUAmount and STAmount arithmetic
  Add tests
  Add implicit conversion from STAmount to Number
  Add clip
  Add conversions between Number, XRPAmount and int64_t
  AMM Add Number class and associated algorithms
* upstream/develop:
  Update documented pathfinding configuration defaults: (XRPLF#4409)
* upstream/develop:
  Rename to fixNonFungibleTokensV1_2 and some cosmetic changes (XRPLF#4419)
  Only account specified as destination can settle through brokerage: (XRPLF#4399)
  Prevent brokered sale of NFToken to owner: (XRPLF#4403)
  Fix 3 issues around NFToken offer acceptance (XRPLF#4380)
  Allow NFT to be burned when number of offers is greater than 500 (XRPLF#4346)
  Add fixUnburnableNFToken feature (XRPLF#4391)
  Change default vote on fixUniversalNumber from yes to no (XRPLF#4414)
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.

This still looks good as far as I can see. Thanks for looking into this problem. 👍

* upstream/develop:
  Resolve a couple of Github Action CI annoyances: (XRPLF#4413)
* upstream/develop:
  README: Add a few source code starting points (XRPLF#4421)
* upstream/develop:
  Fix Conan version constraint in workflows (XRPLF#4430)
  Refactor getTrustedForLedger() (XRPLF#4424)
  README: Update "Build from source" section (XRPLF#4426)
* upstream/develop:
  Undo API changes introduced in XRPFees: (XRPLF#4429)
  Remove recipe for RocksDB and add recipe for Snappy (XRPLF#4431)
@intelliot intelliot requested review from HowardHinnant and removed request for legleux March 1, 2023 17:48
* upstream/develop:
  Set version to 1.10.0-rc4
  Rename 'NFT' to 'NFToken' in DisallowIncoming flags (XRPLF#4442)
  Update Docker.md (XRPLF#4432)
  Update package building scripts and images to use Conan (XRPLF#4435)
  Disable duplicate detector: (XRPLF#4438)
@intelliot
Copy link
Collaborator

@ximinez @mDuo13 This should not be considered a breaking API change, right? It sounds like it may be just a bug fix.

What if someone gets a marker from a rippled server that has this fix and then attempts to use it in a request to an older rippled server?

@ximinez
Copy link
Collaborator Author

ximinez commented Mar 14, 2023

This should not be considered a breaking API change, right? It sounds like it may be just a bug fix.

@intelliot No, it's not a breaking change. The API is already broken. This fixes it. So, yes, bug fix.

What if someone gets a marker from a rippled server that has this fix and then attempts to use it in a request to an older rippled server?

Markers are not intended to be compatible or reusable across different server instances, much less versions. However, it's worth noting that the older rippled servers will provide these markers already - they just can't understand them.

* upstream/develop:
  Set version to 1.10.0
* upstream/develop:
  docs: security bug bounty acknowledgements (XRPLF#4460)
* upstream/develop:
  Rectify the import paths of boost/iterator: (XRPLF#4293)
  Allow port numbers be be specified with a colon: (XRPLF#4328)
  Use <=> operator for base_uint, Issue, and Book: (XRPLF#4411)
  Reporting Mode: Do not attempt to acquire missing data from peer network (XRPLF#4458)
@intelliot intelliot assigned ximinez and unassigned HowardHinnant Mar 17, 2023
@ximinez ximinez added the Passed Passed code review & PR owner thinks it's ready to merge. Perf sign-off may still be required. label Mar 20, 2023
@intelliot intelliot merged commit 9b2d563 into XRPLF:develop Mar 20, 2023
@ximinez ximinez deleted the badmarker branch March 20, 2023 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Added to API Changelog API Change Bug Passed Passed code review & PR owner thinks it's ready to merge. Perf sign-off may still be required. Testable
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

account_lines paginating when there is only one "line" (Version: 1.9.4)
6 participants