Compare commits

..
Author SHA1 Message Date
Ed Hennis b9daf4cb52 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-19 13:22:27 -04:00
Ed Hennis 60df4dc75c Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-19 13:22:22 -04:00
Alex KremerandAyaz Salikhov 3608433514 test: Check error consistently in rpc handlers (#8604)
Co-authored-by: Ayaz Salikhov <[email protected]>
2026-10-19 16:17:30 +00:00
Ed Hennis ad3c2bda5c Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-14 19:01:38 -04:00
Ed Hennis ac49c01dde Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-14 19:01:33 -04:00
Ed Hennis 9001749fc7 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-14 16:57:09 -04:00
Ed Hennis 43915164bd Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-14 16:57:05 -04:00
Ed HennisandCopilot Autofix powered by AI 199c9f6309 Fix typo in comment for SHAMapStoreImp.cpp
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-13 13:37:43 -04:00
Ed Hennis 15ec84140c Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-12 19:13:07 -04:00
Ed Hennis ef6b661d75 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-12 19:13:03 -04:00
Ed Hennis 5a5330b2c8 Check isRotationInFlight twice, before and after reading the archive
- Check before so that if it's cleared during the fetch, the node is not
  lost when the archive DB is deleted. Check after the fetch so that if
  a rotation starts during the fetch, we can be sure this node is
  preserved.
2026-10-12 18:53:20 -04:00
Ed Hennisandxrplf-ai-reviewer[bot] b451cde787 Apply suggestion from @xrplf-ai-reviewer[bot]
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
2026-10-12 18:34:08 -04:00
Ed Hennis beb8f6b3a2 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-12 17:14:34 -04:00
Ed Hennis 80ba0ccd12 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-12 17:14:29 -04:00
Ed Hennis 5eacc2e27e Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-12 16:20:13 -04:00
Ed Hennis ad071f3cd3 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-12 16:20:08 -04:00
Ed Hennis 3e2b40f92d Improve rescue counting, log rotation aborts
* Increment `rescuedCount` within `rescueNode`. Removes the need for
  callers to do it, and ensures it isn't incremented if a node is
  invalid.
* Log "ROTATING: rotation aborted before completion", if the loop ends
  gracefully for any reason before the entire rotation process is
  completed. Distinguishes between crashes and shutdowns or retries.
2026-10-12 15:31:00 -04:00
Ed Hennis e649e91a76 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-09 20:11:06 -04:00
Ed Hennis fca62622e9 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-09 20:11:01 -04:00
Ed Hennis 7e98cc1777 AI review feedback: inFlight race condition
* Initialize inFlight before the backend pointers to avoid race
  conditions.
  > An archive fetch can begin before the swap and finish after rotate()
  > and its scope guard have cleared rotationInFlight_. This check then
  > skips the copy even though the object came from the backend just
  > retired; the fetch can return that object to a SHAMap cache after
  > the old backend is removed, leaving a node in memory with no durable
  > copy.
2026-10-09 20:07:04 -04:00
Ed Hennis 2d8f92aba0 Address review comments: Fix typos, improve comments 2026-10-09 16:20:10 -04:00
Ed Hennis 5b699f07e3 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-08 12:22:03 -04:00
Ed Hennis e4719e8230 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-08 12:21:56 -04:00
Ed Hennis 277f486884 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-07 12:24:30 -04:00
Ed Hennis 3c03945ae9 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-07 12:24:25 -04:00
Ed Hennis 456f6a16aa Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-06 19:13:03 -04:00
Ed Hennis a453b17cdc Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-06 19:12:58 -04:00
Ed Hennis d877605e55 Merge branch 'ximinez/online-delete-gaps2' into ximinez/online-delete-gaps3 2026-10-06 13:18:36 -04:00
Ed Hennis dfcde92c25 Merge branch 'develop' into ximinez/online-delete-gaps2 2026-10-06 13:18:31 -04:00
Ed Hennis 41bae9ce51 Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps2
* XRPLF/develop: (28 commits)
  test: Add more tests for granular permissions (8459)
  fix: Enforce that MPT issuance flags are never cleared (8152)
  feat: Allow lending transactions in Batch (8244)
  feat: Add full support for all objects in `ledger_entry` (6319)
  build: Define XRPL_ASAN, XRPL_TSAN, and XRPL_UBSAN compile definitions (8483)
  refactor: Use LedgerHashesEntry everywhere (8369)
  refactor: Use EscrowEntry everywhere (8354)
  chore: Update nix flake file (8479)
  refactor: Use FeeSettingsEntry everywhere (8370)
  fix: Add string type validation for channel_id and signature (7582)
  test: Migrate three beast suites from beast::unit_test to gtest (7993)
  refactor: Build Throw messages with std::format (8474)
  feat: Implement Confidential mpt holder key update (8266)
  fix: Do not block MPToken deletion on unrelated confidential balances (8209)
  fix: Enable the large Number mantissa with MPTokensV2 (8330)
  chore: Add ignore revs for recent style changes (8463)
  ci: Make release always go into stable channel (8469)
  test: Restore config test environment variables with a guard (8333)
  ci: Add more guardrails for merging releases back to develop (8466)
  feat: Add MPT transaction stream to `subscribe` RPC (5671)
  ...
2026-10-06 13:05:06 -04:00
Ed Hennis 26ab790b71 Merge commit 'ddbc5f1a24' into ximinez/online-delete-gaps2
* commit 'ddbc5f1a24': (78 commits)
  fix: Resolve IntrusivePointer leak (8328)
  chore: CamelCase for typedef/using in `clang-tidy` (8177)
  refactor: Make the config name constants constexpr string views (8332)
  fix: Count cluster traffic only from cluster members (8319)
  fix: Queue a transaction hash only for peers that asked for it (8309)
  docs: Add notes about common acronyms (8298)
  build: Support custom release channel (8326)
  fix: Round up MPT owner cost in book_offers running balance (8213)
  fix: Count cluster messages as cluster traffic (8308)
  build: Publish a Docker image from GitHub (8322)
  refactor: Add initial integration of `rpc-spec` (8284)
  feat: Introduce Cosign v1 amendment with TransactionProposalCreate (8205)
  chore: [DEPENDABOT] bump cxx from 1.0.199 to 1.0.202 in /crates in the rust-dependencies group across 1 directory (8224)
  test: Add source location to MPTTester (8275)
  refactor: Unify `upperBound` and `lowerBound` into `boundHelper` (7943)
  test: Clean up ConfidentialTransfer test helpers (8265)
  style: Precommit hook for gtest naming (8026)
  fix: Add CTID to ledger command expanded transactions (6401)
  test: Share peer test doubles across the overlay and app suites (8246)
  feat: Support ConfidentialMPTMirrorUpdate (8192)
  ...
2026-10-06 13:04:58 -04:00
Ed Hennis 625779954f Update log messages that the tests added in #8137 are waiting for 2026-10-06 12:38:10 -04:00
Ed Hennis 336d5fb970 Merge commit '827b50f169eeb53b3f5696e7b01079c5d6a8940e' into ximinez/online-delete-gaps2
* commit '827b50f169eeb53b3f5696e7b01079c5d6a8940e':
  fix: Flaky online delete tests, and cover the health checks added in 5531 (8137)
2026-10-06 12:26:09 -04:00
Ed Hennis 4918df605d Merge commit '827b50f169eeb53b3f5696e7b01079c5d6a8940e~' into ximinez/online-delete-gaps2
* commit '827b50f169eeb53b3f5696e7b01079c5d6a8940e~': (48 commits)
  fix: Add signature prefixes for sfCounterpartySignature and sfSponsorSignature (8162)
  build: Verify glibc version was determined in debian package (8170)
  fix: Recycle the escrow reserve in EscrowCancel and EscrowFinish (8142)
  ci: Update pre-commit SHA (8169)
  docs: Use consistent heading levels in PR template (8155)
  ci: Update prepare-runner SHA (8168)
  fix: Correct and simplify Linux packaging (8165)
  fix: Reinforce the priority of AMMClawback in case of insufficient reserves (7796)
  fix: PermissionedDEX (CreateOffer/Payment) never deletes expired credentials (6827)
  fix: Clamp the depth used to index selectBranch's key byte (7941)
  fix: Revert credential cleanup for pseudo-accounts (8161)
  fix: Allow zero-value MPT vault withdraw when the asset holding is missing (8153)
  fix: Treat an existing IOU line as a no-op in addEmptyHolding (8154)
  docs: Add AGENTS.md/CLAUDE.md for AI coding agent guidance (8067)
  fix: Add 60s buffer before closed-ended vault redemption (8151)
  fix: Correct fee-payer XRP delta in ValidVault for sponsored VaultWithdraw (8141)
  fix: Keep LoanBrokerDelete valid for auth-required MPT cover (8144)
  fix: Unblock VaultSet and cash-basis LoanSet at AssetsMaximum (8143)
  fix: Keep VaultDeposit share count after the assetsTotal clamp (8140)
  refactor: Add common helper function for injected metadata fields in RPCs (5706)
  ...
2026-10-06 12:10:41 -04:00
Ed Hennis 76fc155243 Merge commit '764cbe7c295637e56c383ccf0c83313961328d43' into ximinez/online-delete-gaps2
* commit '764cbe7c295637e56c383ccf0c83313961328d43':
  perf: Pause online delete if there any gaps in recent ledger history (5531)
2026-10-06 12:08:36 -04:00
Ed Hennis 74158c3175 Merge commit 'd2dd019735cffeeb6aa1042cd8ab5b7ea2dfadf8' into ximinez/online-delete-gaps2
* commit 'd2dd019735cffeeb6aa1042cd8ab5b7ea2dfadf8':
2026-10-05 18:02:36 -04:00
Ed Hennis d2dd019735 Merge commit '764cbe7c295637e56c383ccf0c83313961328d43~' into HEAD
* commit '764cbe7c295637e56c383ccf0c83313961328d43~':
  fix: Remove credentials pinned to Vault, LoanBroker, and AMM pseudo-accounts (7877)
  fix: Tighten destination checks on vault withdrawal (7977)
2026-10-05 18:01:58 -04:00
Ed Hennis e91d5999ec Merge commit '764cbe7c295637e56c383ccf0c83313961328d43~' into ximinez/online-delete-gaps2
* commit '764cbe7c295637e56c383ccf0c83313961328d43~':
  fix: Remove credentials pinned to Vault, LoanBroker, and AMM pseudo-accounts (7877)
  fix: Tighten destination checks on vault withdrawal (7977)
2026-10-05 17:52:40 -04:00
Ed Hennis 814d14ad2b feat: Log number of nodes rescued during rotation 2026-08-22 15:29:17 -04:00
Ed Hennis e7cfc46275 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-21 17:28:58 -04:00
Ed Hennis c3c555c260 Ensure getAndResetDuplicationCount() is always called after copyNodes 2026-08-21 17:27:15 -04:00
Ed Hennis 3cc27a4a67 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  Add a 1/4s delay so the server doesn't restore the removed ledger
  Reapply "experiment: find where the deleted ledger is being put back"
  fix: Add assert for account_info flags (7987)
2026-08-21 15:13:13 -04:00
Ed Hennis 17bec9e4d4 fixup! Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-21 15:12:25 -04:00
Ed Hennis 0e54845db0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-21 14:27:08 -04:00
Ed Hennis 6f1f53a152 Add a 1/4s delay so the server doesn't restore the removed ledger
- Delay before removing the ledger index so the server can get all its
  record keeping done before I mess with it.
2026-08-21 14:25:01 -04:00
Ed Hennis 080ad9fe34 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  Revert "experiment: find where the deleted ledger is being put back"
2026-08-21 12:15:45 -04:00
Ed Hennis 2620ae59ae Reapply "experiment: find where the deleted ledger is being put back"
- It's Schrodinger's ledger index. Not checking that it's removed allows
  it to be put back.

This reverts commit 77793df659.
2026-08-21 12:13:59 -04:00
Ed Hennis d3d5f39787 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  fix: Reject vault deposits that move nothing from the depositor (8014)
  experiment: find where the deleted ledger is being put back
  clang-tidy: Use switch. Duh
  Fix timing issues in the gap test
  perf: Speed up addition time for drastically different exponents (7825)
  refactor: Collapse transactions.macro settings into a TxSettings struct (8001)
  fix: Enforce MPT balance invariants under the latest cleanup amendment (7889)
  fix: Prevent AMM auction slots from being acquired at zero cost when trading fee is zero (7430)
  docs: Fix yum installation baseurl (8066)
  fix: Return specific and consistent errors from vault_info (8015)
  ci: Save cargo cache only from develop by default (8063)
  fix: Check credential for LoanBrokerCoverWithdraw and VaultWithdraw (7107)
  build: Suppress MSVC linker warning LNK4099 (8049)
  chore: [DEPENDABOT] Bump cxx from 1.0.198 to 1.0.199 in /crates in the rust-dependencies group across 1 directory (8050)
  build: Use debian `any` distribution & signed (hosted) rpm repo (8053)
  ci: Do not cache cargo binaries (8062)
2026-08-21 11:40:03 -04:00
Ed Hennis 77793df659 Revert "experiment: find where the deleted ledger is being put back"
This reverts commit e67e9f6660.
2026-08-21 11:36:56 -04:00
Ed Hennis 6abcc9fe1a Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  fix: Reject vault deposits that move nothing from the depositor (8014)
  perf: Speed up addition time for drastically different exponents (7825)
  refactor: Collapse transactions.macro settings into a TxSettings struct (8001)
2026-08-21 11:35:50 -04:00
Ed Hennis e67e9f6660 experiment: find where the deleted ledger is being put back 2026-08-20 22:48:39 -04:00
Ed Hennis 6718b3276b clang-tidy: Use switch. Duh 2026-08-20 21:29:34 -04:00
Ed Hennis 642dbad885 Fix timing issues in the gap test
- The coverage build exposed that the timing was more sensitive than
  I had thought. Force things to run in the order I expect by changing
  the server mode (via NetworkOPs::setMode).
2026-08-20 21:07:10 -04:00
Ed Hennis 833433b25e Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-20 15:39:42 -04:00
Ed Hennis 84e32ed33c Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  clang-tidy: exclude 2 rules from rotation functionality
  Minor fixes from AI code review
2026-08-19 18:24:01 -04:00
Ed Hennis 23369e114a clang-tidy: exclude 2 rules from rotation functionality
- readability-else-after-return
- readability-braces-around-statements
2026-08-19 18:08:01 -04:00
Ed Hennis d3d0c6366a Minor fixes from AI code review 2026-08-19 17:35:53 -04:00
Ed Hennis c15c7bfd54 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-19 12:57:56 -04:00
Ed Hennis af61140cd9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-19 12:57:51 -04:00
Ed Hennis 4e1de43939 clang-tidy: Make changes uglier by adding a bunch of redundant {}s 2026-08-19 11:42:59 -04:00
Ed Hennis dc71651429 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  More review feedback from @vlntb: log warnings after a delay
  Review feedback from @vlntb: Circuit breaker
  build: Use AlmaLinux for the RHEL packaging image (8045)
  build: Run nix macos builds in CI; deny nix store references (8023)
  fix: Enable reserve checking on ending sponsorship (8044)
  fix: Add ValidPermissionedDEX invariant track for fully consumed offer (6736)
  AI review feedback: validate config, improve healthWait()
  test: Split Vault_test into topical suites under src/test/app/vault/ (8041)
  fix: Fix assorted NFT and pDEX bugs (7749)
  chore: Publish debian/rpm packages from GitHub directly (8031)
  refactor: Add `SHAMapNodeID::isPrefixOf` (7939)
  fix: Conserve funds correctly when LoanPay fee payee is below reserve (7843)
2026-08-18 21:33:11 -04:00
Ed Hennis e372201499 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-18 21:27:07 -04:00
Ed Hennis 8b2a7f6253 More review feedback from @vlntb: log warnings after a delay
- Log the "waiting" messages at warning level once the delay reaches 1/4
  of the way to the circuit breaker cutoff.
- Also fix the exception message on configuration validation.
2026-08-18 21:15:52 -04:00
Ed Hennis 6211dbd1cc Review feedback from @vlntb: Circuit breaker
- Adds a "max_waiting_ledgers" config, which defaults to the
  "online_delete" value. If the rotation gets stuck for that number of
  ledgers, abort the rotation and try again later. The existing gap will
  be ignored on the next rotation.
- Create a new HealthResult::Expired. Update most healthWait() call
  sites to account for the new possible result. Pay special note to the
  calls in SHAMapStoreImp::run() to ensure they don't exit the thread
  prematurely, or keep rotating when they should not.
- Did a little clean up while I was in there.
- Update tests.
2026-08-18 20:46:06 -04:00
Ed Hennis d89063acae AI review feedback: validate config, improve healthWait()
- Check that recovery_wait_time is non-zero.
- In healthWait(), explicitly check whether the only missing ledger is
  the current validated ledger, in the process of being built. If so,
  log lower, and only wait 1/10 of the time.
- Add the special case from #7793 that will let rotation run if the node
  is disconnected.
2026-08-18 15:48:34 -04:00
Ed Hennis 0e328d8277 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-17 22:36:53 -04:00
Ed Hennis 7d55bb7d8e Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-17 22:36:49 -04:00
Ed Hennis 14c190fd31 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-14 19:24:18 -04:00
Ed Hennis efe843d6b2 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-14 19:24:14 -04:00
Ed Hennis 41e422d2c1 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-13 16:01:23 -04:00
Ed Hennis 7f10f3938f Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-13 16:01:19 -04:00
Ed Hennis 9c8b45f0ed Add an instrumentation check for Antithesis 2026-08-12 18:04:53 -04:00
Ed Hennis f7e96beba7 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-12 15:36:55 -04:00
Ed Hennis 5a7a715283 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-12 15:36:50 -04:00
Ed Hennis 8f1974d0ec Review feedback from @sophiax851: inFlight back to bool
- Convert the inFlight tracking to a simple bool instead of ledger
  index. In testing, almost no nodes were skipped anyway, so it's not
  a signficant factor.
- Reset the duplicate node count when reading it.
- Update some comments and logging.
2026-08-11 22:09:30 -04:00
Ed Hennis f84e07427c Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-10 21:37:12 -04:00
Ed Hennis d375fa356f Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-10 21:37:07 -04:00
Ed Hennis 5d5e4d3405 AI review feedback: logging, documentation / comments
- Also, use ScopeExit instead of a custom local guard class to reset
  rotationInFlight.
2026-08-10 21:18:30 -04:00
Ed Hennis 1eacb33d72 Revert "Update assert label in src/xrpld/app/misc/SHAMapStoreImp.cpp"
This reverts commit fafc48bda3.
2026-08-10 21:14:58 -04:00
Ed Hennisandxrplf-ai-reviewer[bot] fafc48bda3 Update assert label in src/xrpld/app/misc/SHAMapStoreImp.cpp
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
2026-08-10 20:44:43 -04:00
Ed Hennis 9a2b6866a7 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-10 20:39:09 -04:00
Ed Hennis 8a49f93b78 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-10 20:39:05 -04:00
Ed Hennis c5c85eef48 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-10 15:04:38 -04:00
Ed Hennis 5aed870ff0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-10 15:04:32 -04:00
Ed Hennis 0fe2be63f4 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-07 17:32:10 -04:00
Ed Hennis 4c93c8d5be Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-07 17:32:06 -04:00
Ed Hennis 5817d3547e Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps: (36 commits)
  chore: Bump version to 3.4.0-b0 (7976)
  chore: Bump version to 3.3.0
  chore: Bump version to 3.3.0-rc7
  fix: Increase manifest protocol message size cap and fix manifests relay
  fix: Cap untrusted manifests per message and drop oversized ones
  chore: Bump version to 3.3.0-rc6
  feat: Package validator-keys inside rippled
  chore: Bump version to 3.3.0-rc5
  fix: Switch SponsorshipSet to use a delta for sfFeeAmount
  fix: Re-revert "fix: Set request size limits and differential pricing for get-object-by-hash calls"
  chore: Bump version to 3.3.0-rc4
  fix: Revert "fix: Set request size limits and differential pricing for get-object-by-hash calls"
  chore: Bump version to 3.3.0-rc3
  fix: Reduce untrusted manifest cache cap to 100
  fix: Revert "fix: Reject oversized SHAMap nodes in gotStaleData and fetch-pack path"
  chore: Bump version to 3.3.0-rc2
  fix: Check transaction type before RawTransactions
  fix: Change ConfidentialMPTConvert to no delegate
  fix: Bound untrusted manifest cache
  feat: Make DynamicMPT opt-in-immutable
  ...
2026-08-07 14:23:15 -04:00
Ed Hennis 7a8d86b0b1 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-07 13:38:10 -04:00
Ed Hennis 1bbe54ad60 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-07 12:02:27 -04:00
Ed Hennis 0bb9716784 clang-tidy fixes: includes and explicit struct field names 2026-08-06 15:22:32 -04:00
Ed Hennis 295c71b007 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-06 14:14:43 -04:00
Ed Hennis 78f3148e4c Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-06 14:14:38 -04:00
Ed Hennis 894263bb89 Update renamed namespace 2026-08-05 22:49:46 -04:00
Ed Hennis 9de4e7e58d Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-05 12:17:07 -04:00
Ed Hennis ec844351d9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-05 12:17:03 -04:00
Ed Hennis 41b4cf36e6 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-08-04 19:41:56 -04:00
Ed Hennis 6f7ad510e3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-08-04 19:41:52 -04:00
Ed Hennis 5db10a4d3b Merge branch 'release/3.2.x' into ximinez/online-delete-gaps2
* release/3.2.x:
  chore: Bump version to 3.2.1
  chore: Bump version to 3.2.1-rc1
  fix: Cap untrusted manifests per message and drop oversized ones
  fix: Reject oversized validator manifest before decoding
  fix: Reduce untrusted manifest cache cap to 100
  fix: Bound untrusted manifest cache
2026-07-31 22:53:33 -04:00
Ed Hennis 919cfd5f49 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-07-31 10:01:28 -04:00
Ed Hennis 476a64d5ce Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-31 10:01:23 -04:00
Ed Hennis 303952aeb4 Merge branch 'ximinez/online-delete-gaps' into ximinez/online-delete-gaps2 2026-07-30 15:41:40 -04:00
Ed Hennis 85a6dfee1f Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-30 15:41:18 -04:00
Ed Hennis 621f876337 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  Update lastLedger in the healthWait loop in the right order
2026-07-27 22:57:28 -04:00
Ed Hennis da2f36c8a6 Update lastLedger in the healthWait loop in the right order 2026-07-27 22:47:33 -04:00
Ed Hennis fab69c28d2 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  chore: Move semantic version tests to gtest (7872)
  style: Make clang-tidy format files using clang-format rules (7880)
  ci: Change `server_definitions` upload config name (7878)
  chore: Trivial gtest migrations (7865)
  ci: Group github-actions dependabot updates (7876)
  ci: Update CI image and prepare-runner action (7874)
  test: Migrate `nodestore` tests from Beast to GTest (7292)
  test: Improve the server status test to not race and randomly fail (7304)
  ci: [DEPENDABOT] bump actions/checkout from 7.0.0 to 7.0.1 (7871)
  chore: Fix clang version in devshell (7860)
  chore: Verify tooling version for Nix-managed environments (7862)
2026-07-27 18:33:07 -04:00
Ed Hennis afedf445f0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-27 17:00:51 -04:00
Ed Hennis fe1b1c8f92 Count the number of explicitly duplicated nodes, and log it
- The "copied ledger" count may differ from the "Rotating:" count,
  because the latter will also count nodes from the cache.
2026-07-24 19:55:03 -04:00
Ed Hennis e61b134742 Rescue node from copyNode as NodeType::AccountNode
- Nodes rescued from freshenCaches are checked dynamically, and not
  written if not AccountNode.
2026-07-24 18:34:24 -04:00
Ed Hennis 2ba3edaf14 Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  build: Patсh binary in local Linux nix environment (7859)
2026-07-24 11:55:11 -04:00
Ed Hennis 7cf063b1d8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-24 11:54:19 -04:00
Ed Hennis 5f087f6446 Improve node store rotation
- Add a special case to healthWait() to not pause when the server is
  DISCONNECTED.
- Log sequence differences at the start and end of rotation.
- Limit copy-forward to ledgers we're not about to delete, and unknown.
  (Changes rotationInFlight_ from a bool to a LedgerIndex.)
- Set the "rotation in flight" index right at the beginning of the rotation
    - Because the node copy process can take a long time, other ledgers may
      get validated. Any reads for those ledgers have the potential to be
      served by the archive DB and thus lost, too. Why wait?
- Add an assertion suggested on @vlntb in #7763.
- Don't wait as long for ledgers that should be built soon.
- Rescue nodes from the tree node cache, too.
2026-07-23 21:17:06 -04:00
Ed Hennis a2446e8f99 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-23 20:08:50 -04:00
Ed Hennis 6accc87a10 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-22 20:40:49 -04:00
Ed Hennis 313d0d188b Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-22 13:54:28 -04:00
Ed Hennis 53dc3b4051 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-21 14:10:04 -04:00
Ed Hennis b589985dae Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-20 17:23:09 -04:00
Ed Hennis 180c979835 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-20 12:45:06 -04:00
Ed Hennis 88665a6de0 clang-format: remove unused header 2026-07-17 19:11:42 -04:00
Ed Hennis 66526a8a48 AI review feedback: clean up, enforce parameter validity, tests 2026-07-16 20:28:33 -04:00
Ed Hennis 18c11097b6 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-16 14:29:48 -04:00
Ed Hennis bfe54849c9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-15 19:12:13 -04:00
Ed Hennis 831ac87627 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-15 11:28:12 -04:00
Ed Hennis 1b7af3165d Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-14 20:25:39 -04:00
Ed Hennis 48ca6e0025 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-14 13:48:02 -04:00
Ed Hennis 0047ed4db2 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-13 17:22:24 -04:00
Ed Hennis 6dc73cb528 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-13 15:07:28 -04:00
Ed Hennis 7f58c3d7d6 Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  test: Add tests for check doxygen style (7795)
  style: Add pre-commit hook to check doxygen style (7794)
  style: Unify style for all Doxygen comments (7776)
2026-07-13 12:21:59 -04:00
Ed Hennis 86f52c412c Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-12 18:38:08 -04:00
Ed Hennis 4dce2f22b6 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-08 17:23:11 -04:00
Ed Hennis fe8368b970 Update test to ensure correct starting conditions 2026-07-07 20:26:55 -04:00
Ed Hennis d68273c755 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-07 19:32:20 -04:00
Ed Hennis df489c7a6e Tweak log message levels
- lastGoodValidatedLedger_ update is now trace.
- Log the first healthWait failure for a given validated ledger as
  trace.
2026-07-07 17:29:42 -04:00
Ed Hennis b45038f70a Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-07 15:50:15 -04:00
Ed Hennis 44cc4e656f Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-06 13:32:00 -04:00
Ed Hennis ac3435bf0a Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-02 19:03:48 -04:00
Ed Hennis bd2f5dbd35 AI review feedback: variable initialization, comments, headers 2026-07-02 19:01:51 -04:00
Ed HennisandCopilot Autofix powered by AI 4644347d21 Apply suggestions from code review: fix typos
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-07-02 18:48:43 -04:00
Ed Hennis e34e05ebec Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  refactor: Retire DisallowIncomingV1 fix (7364)
  build: Add verify-headers target to cleanup headers (7670)
2026-07-02 11:17:33 -04:00
Ed Hennis 9b22c6c80b Reorganize healthWait to avoid deadlock and duplicated code 2026-07-01 18:38:03 -04:00
Ed Hennis d4e166bbdc Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-01 13:24:20 -04:00
Ed Hennis b80776b0fe Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-30 14:38:54 -04:00
Ed Hennis 9af4fb521e Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-29 20:05:54 -04:00
Ed Hennis 7ee290674c Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-25 11:43:17 -04:00
Ed Hennis 68f050b186 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-24 19:59:59 -04:00
Ed Hennis 2be13c18a1 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-23 11:09:48 -04:00
Ed Hennis df5fa5aade Correct a couple of comments 2026-06-22 16:48:00 -04:00
Ed Hennis 51ef3a7343 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-22 16:41:46 -04:00
Ed Hennis dd4eca22b7 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-17 15:01:23 -04:00
Ed Hennis 1116dbfd0e Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-16 18:56:01 -04:00
Ed Hennis 258d5e1f1f clang-tidy: nodiscard rendezvous, headers, const correctness, {}s 2026-06-16 18:47:40 -04:00
Ed Hennis 4270367efc Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-15 21:32:49 -04:00
Ed Hennis fad34e852d More AI review feedback:
- Move a log message into the same block as the thing it's logging.
- Change default recovery time from 1s to 2s. This may need some more
  tuning.
- Rename the online_delete test config helper function to onlineDelete.
- Copy some class values while under lock, even though they can't
  change, as defense in depth.
- Use RAII scope unlock in healthWait().
2026-06-15 21:28:23 -04:00
Ed Hennis f5b4ac358f AI review feedback
- Remove extraneous function declaration.
- Add a timeout to SHAMapStore_test::testLedgerGaps so it won't hang in
  case of regression.
- Add an optional timeout parameter to SHAMapStore::rendezvous, and
  return a success flag.
  - Use the timeout in SHAMapStore_test::testLedgerGaps to show lack of
    progress in the Store without an arbitrary sleep delay.
- Refactor LedgerMaster::missingFromCompleteLedgerRange to use RangeSet
  functions instead of a naive iteration.
- If lastGoodValidatedLedger_ is default (0) in healthWait(), then act
  as if no ledgers are missing.
2026-06-15 20:13:40 -04:00
Ed Hennis 875bcc530e Correct a couple of variable names 2026-06-15 16:47:29 -04:00
Ed Hennis e75f5b101b Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-15 15:28:44 -04:00
Ed Hennis 95f74d61b2 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-15 12:11:54 -04:00
Ed Hennis 4e12b787be Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop: (22 commits)
  test: Add null check unit test for `Oracle::aggregatePrice` (7306)
  ci: Patch conan recipe for Nix to be able to use on macOS (7532)
  ci: Run sanitizers on release builds too (7527)
  fix: Correct hybrid offer deletion on credential expiry (6843)
  ci: Make sanitizer flags lists in the profile, not a string (7449)
  ci: Make configurations launch on certain event types (7447)
  fix: Add [[maybe_unused]] to fix320Enabled for assert=OFF builds (7446)
  ci: Add `gh` and `file` to nix packages (7444)
  fix: Disable transaction invariants (7409)
  perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast (7402)
  refactor: Retire fixUniversalNumber amendment (5962)
  test: Do not create data directory for memory databases (7323)
  ci: Launch upload-conan-deps on profile change (7442)
  fix: Fix Number comparison operator (7406)
  feat: Use C++ 23 standard (7431)
  refactor: Introduce XRPL_ASSERT_IF for amendment-gated assertions (7378)
  refactor: Change config section and key string literals into constants (7095)
  refactor: Use `std::move` and `std::string_view` where possible (7424)
  refactor: Use const function arguments where possible (7423)
  ci: Use XRPLF/actions build-multiarch-image workflow (7428)
  ...
2026-06-11 21:34:19 -04:00
Ed Hennis 8b6c80027b Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-05 18:48:40 -04:00
Ed Hennis ace73678cf Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-04 13:32:19 -04:00
Ed Hennis 12bbba00b0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-04 10:08:25 -04:00
Ed Hennis 2affb66f50 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-02 11:58:29 -04:00
Ed Hennis d09e785c39 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-01 14:24:26 -04:00
Ed Hennis 97fdf310f9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-28 23:47:49 -04:00
Ed Hennis d3ce76825c Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-27 17:00:52 -04:00
Ed Hennis 1e7e274727 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-27 15:18:10 -04:00
Ed Hennis b272d71cc7 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-27 12:06:52 -04:00
Ed Hennis 21268d9c36 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-26 19:20:55 -04:00
Ed Hennis 932e22df7d Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-26 16:56:36 -04:00
Ed Hennis 652a7cd225 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-26 16:01:32 -04:00
Ed Hennis 4a224dbfa4 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-22 17:56:07 -04:00
Ed Hennis d2a5981f87 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-21 14:25:41 -04:00
Ed Hennis a977836630 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-21 10:09:42 -04:00
Ed Hennis bf075200bb Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  docs: Add --parallel flag to cmake build commands in BUILD.md (7302)
  fix: Fix wrong hybrid offer orderbook placement and update `LedgerStateFix` to amend `ExchangeRate` meta (7087)
  style: More clang-tidy identifier renaming (7290)
  fix: Update pDEX invariant firing under a valid offer deletion (7118)
  fix: Fix multisign and signfor to check for delegate (7064)
  refactor: Fix `sfGeneric` and `sfInvalid` field names (7300)
  docs: Fix some comments to improve readability (7122)
  feat: Propagate underlying MPT flags to vault shares (7077)
2026-05-21 11:59:26 +01:00
Ed Hennis ee49e76a16 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-19 16:53:27 -04:00
Ed Hennis c1318990f3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-19 10:15:02 -04:00
Ed Hennis 69128294f8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-19 05:15:40 -04:00
Ed Hennis 149e884ebc Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-15 21:32:03 -04:00
Ed Hennis d27353225c Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  release: Set version to 3.3.0-b0 (7280)
  refactor: Rename static constants (7120)
  refactor: Use `isFlag` where possible instead of bitwise math (7278)
  ci: Update XRPLF/actions (7281)
2026-05-15 15:47:01 -04:00
Ed Hennis 13a0f77eb5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-14 20:39:04 -04:00
Ed Hennis 549c093398 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-13 20:16:12 -04:00
Ed Hennis fb66ca7a2e Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-13 12:03:27 -04:00
Ed Hennis e2af73b0a0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-12 19:18:39 -04:00
Ed Hennis 14c3c9a256 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-12 16:26:02 -04:00
Ed Hennis 4b6851a287 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-12 15:59:13 -04:00
Ed Hennis d182673d24 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-11 13:33:56 -04:00
Ed Hennis bea609d805 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-07 18:09:54 -04:00
Ed Hennis 56eeb20bc8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-07 14:18:14 -04:00
Ed Hennis e293a3d918 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-07 13:28:18 -04:00
Ed Hennis 3dff580d39 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-06 22:34:11 -04:00
Ed Hennis 487f5a0fd3 clang-tidy fix: lock_guard -> scoped_lock 2026-05-06 18:44:16 -04:00
Ed Hennis d8134f98e9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-06 14:17:47 -04:00
Ed Hennis 450a623d4b Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-05 16:46:26 -04:00
Ed Hennis 9e517be4ce Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-05 10:50:18 -04:00
Ed Hennis b8370438fb Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  ci: Rewrite clang-tidy workflow(s) in a reusable manner (7062)
  chore: Ignore identifier-naming update in git blame (7066)
  refactor: Enable clang-tidy `readability-identifier-naming` check (6571)
2026-05-04 21:36:05 -04:00
Ed Hennis ecb5604d3b Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-01 12:54:31 -04:00
Ed Hennis c4527e7b0f Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  fix: Gate -mcmodel flags to x86_64 in sanitizer builds (7049)
  fix: Prevents overwriting a bool value in an invariant (6609)
  fix: Address code review comments regarding `boost::coroutine2` (6977)
  refactor: Apply various minor improvements and corrections (7045)
  fix: Store `Delegate` object in delegating and authorized account directories for proper deletion (6681)
  ci: Use print-env from XRPLF/actions (7052)
  fix: Make assorted RPC fixes (6529)
  chore: Enable clang-tidy v21 new checks (7031)
2026-04-30 14:30:36 -04:00
Ed Hennis 778e2b3ce8 Fix clang-tidy: missing include 2026-04-28 15:44:14 -05:00
Ed Hennis 295d03aec8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-28 16:23:08 -04:00
Ed Hennis 9262c2e624 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-25 14:41:57 -04:00
Ed Hennis b385a41aa5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-23 15:55:43 -04:00
Ed Hennis 4eb9726097 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-22 23:39:00 -04:00
Ed Hennis 28a38ef1cc Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-22 14:48:51 -04:00
Ed Hennis 39f9380b2b Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-22 11:36:03 -04:00
Ed Hennis 239fcaceb4 clang-tidy fix: Use std::to_string for std::uint32_t 2026-04-21 19:30:05 -04:00
Ed Hennis 8ab86f009e Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-21 18:47:53 -04:00
Ed Hennis d4b58a74f4 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-21 14:37:52 -04:00
Ed Hennis ff900591ae Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-21 10:40:45 -04:00
Ed Hennis a5b7471af6 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-20 17:49:20 -04:00
Ed Hennis e0734986dd Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-20 15:44:37 -04:00
Ed Hennis 8440f479e5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-20 11:37:54 -04:00
Ed Hennis ac390622e0 Fix clang-tidy issues 2026-04-17 17:54:37 -04:00
Ed Hennis 5d807f0d6d Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  chore: Enable clang-tidy include cleaner (6947)
  fix: Change AMMClawback return code to tecNO_PERMISSION (6946)
  ci: [DEPENDABOT] bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 (6927)
  ci: [DEPENDABOT] bump actions/upload-artifact from 7.0.0 to 7.0.1 (6928)
  chore: Enable clang-tidy readability checks (6930)
2026-04-17 15:23:33 -04:00
Ed Hennis b93294f26b Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-16 13:44:23 -04:00
Ed Hennis ef95ace0f9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-15 19:06:15 -04:00
Ed Hennis fc58bf6edf Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-15 14:28:41 -04:00
Ed Hennis 348555d5ba Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-13 20:28:29 -04:00
Ed Hennis 302802e42d Fix clang-tidy issues 2026-04-13 20:23:23 -04:00
Ed Hennis 5d881f87a3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-10 12:12:27 -04:00
Ed Hennis a8a8035b32 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-10 09:10:39 -04:00
Ed Hennis 45af14231f Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-09 11:39:55 -04:00
Ed Hennis 380bf274d0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-08 16:56:56 -04:00
Ed Hennis 460ec5eeea Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-08 15:12:46 -04:00
Ed Hennis 14be8ca4ea Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-07 16:47:32 -04:00
Ed Hennis 948264d44c Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 19:06:51 -04:00
Ed Hennis 9c816b2043 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 18:33:20 -04:00
Ed Hennis f68402acd1 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 16:52:50 -04:00
Ed Hennis 5358e25eaa Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 13:24:22 -04:00
Ed Hennis a34d1e5537 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-01 17:26:14 -04:00
Ed Hennis 78a122943d Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-01 13:39:05 -04:00
Ed Hennis 06135e7203 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-01 11:45:32 -04:00
Ed Hennis f20425fa4f Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-30 21:29:37 -04:00
Ed Hennis 3e94546acc Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-12 15:05:04 -04:00
Ed Hennis 3b088ed0dc Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-10 12:46:18 -04:00
Ed Hennis 26182ed52e Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-06 13:04:00 -04:00
Ed Hennis de2a3e10f5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-05 21:34:29 -04:00
Ed Hennis e17f8554fc Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-04 17:11:27 -04:00
Ed Hennis 386a7192ba Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-03 20:46:41 -04:00
Ed Hennis 12cc6e424d Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-03 15:54:32 -04:00
Ed Hennis c9deecf1b7 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-24 17:34:32 -04:00
Ed Hennis ddd1b49f38 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-24 16:45:55 -04:00
Ed Hennis c1b2a24005 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 18:49:39 -04:00
Ed Hennis 86d88eca31 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 18:25:58 -04:00
Ed Hennis ef09eaea00 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 17:31:41 -04:00
Ed Hennis c504cfb291 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 17:21:03 -04:00
Ed Hennis 0c217dfa2b Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 15:14:23 -04:00
Ed Hennis b0198d2566 Merge remote-tracking branch 'upstream/develop' into ximinez/online-delete-gaps
* upstream/develop:
  ci: Add dependabot config (6379)
  Fix tautological assertion (6393)
  chore: Apply clang-format width 100 (6387)
2026-02-20 12:20:07 -05:00
Ed Hennis 7eee8ca802 Update formatting 2026-02-20 12:15:30 -05:00
Ed Hennis 2a079a0154 Merge commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c' into ximinez/online-delete-gaps
* commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c':
  chore: Set clang-format width to 100 in config file (6387)
2026-02-20 12:12:56 -05:00
Ed Hennis 40989c1178 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-19 16:21:11 -05:00
Ed Hennis addc831eb3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-18 18:06:20 -04:00
Ed Hennis b4efc6d116 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-04 16:29:49 -04:00
Ed Hennis 125d075d6e Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-04 14:16:24 -04:00
Ed Hennis 370a775479 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-03 16:07:47 -04:00
Ed Hennis 1a2ee706eb Fix formatting 2026-01-28 19:43:23 -05:00
Ed Hennis 2a981357ba Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-28 18:40:24 -04:00
Ed Hennis 1ae475e724 Merge commit '5f638f55536def0d88b970d1018a465a238e55f4' into ximinez/online-delete-gaps
* commit '5f638f55536def0d88b970d1018a465a238e55f4':
  chore: Set ColumnLimit to 120 in clang-format (6288)
2026-01-28 17:38:29 -05:00
Ed Hennis a3e9401fbc Merge commit '92046785d1fea5f9efe5a770d636792ea6cab78b' into ximinez/online-delete-gaps
* commit '92046785d1fea5f9efe5a770d636792ea6cab78b':
  test: Fix the `xrpl.net` unit test using async read (6241)
  ci: Upload Conan recipes for develop, release candidates, and releases (6286)
  fix: Stop embedded tests from hanging on ARM by using `atomic_flag` (6248)
  fix:  Remove DEFAULT fields that change to the default in associateAsset (6259) (6273)
  refactor: Update Boost to 1.90 (6280)
  refactor: clean up uses of `std::source_location` (6272)
  ci: Pass missing sanitizers input to actions (6266)
  ci: Properly propagate Conan credentials (6265)
  ci: Explicitly set version when exporting the Conan recipe (6264)
  ci: Use plus instead of hyphen for Conan recipe version suffix (6261)
  chore: Detect uninitialized variables in CMake files (6247)
  ci: Run on-trigger and on-pr when generate-version is modified (6257)
  refactor: Enforce 15-char limit and simplify labels for thread naming (6212)
  docs: Update Ripple Bug Bounty public key (6258)
  ci: Add missing commit hash to Conan recipe version (6256)
  fix: Include `<functional>` header in `Number.h` (6254)
  ci: Upload Conan recipe for merges into develop and commits to release (6235)
  Limit reply size on `TMGetObjectByHash` queries (6110)
  ci: remove 'master' branch as a trigger (6234)
  Improve ledger_entry lookups for fee, amendments, NUNL, and hashes (5644)
2026-01-28 17:38:13 -05:00
Ed Hennis 9091469f9e Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-15 13:03:03 -04:00
Ed Hennis 17fa54f1f9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-15 12:05:41 -04:00
Ed Hennis 8fb5347c2d Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-14 19:20:11 -04:00
Ed Hennis 6739bf998f Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-13 18:04:18 -04:00
Ed Hennis 6eea38ba67 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-13 16:15:44 -04:00
Ed Hennis e9cf88b359 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-13 15:01:56 -04:00
Ed Hennis 645b203476 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-12 21:07:23 -04:00
Ed Hennis be2aff1f4c Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-12 14:51:34 -04:00
Ed Hennis 56ed237e82 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-11 00:48:27 -04:00
Ed Hennis fd7b0fd135 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-08 17:05:28 -04:00
Ed Hennis e700994891 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-08 13:03:41 -04:00
Ed Hennis c76f7029ac Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  test: add more tests for `ledger_entry` RPC (5858)
  refactor: Rename `rippled.cfg` to `xrpld.cfg` (6098)
  Revert "chore: Pin ruamel.yaml<0.19 in pre-commit-hooks (6166)" (6167)
  chore: Pin ruamel.yaml<0.19 in pre-commit-hooks (6166)
  fix: Remove cryptographic libs from libxrpl Conan package (6163)
2026-01-06 11:27:23 -05:00
Ed Hennis d535c5fb2a Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-22 17:39:25 -05:00
Ed Hennis 54f860463e Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-18 18:15:15 -05:00
Ed Hennis 950434b8ff Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-17 12:12:39 -05:00
Ed Hennis ee365e876d Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-12 20:34:29 -05:00
Ed Hennis c6c59834b9 Update View info() to header() 2025-12-12 15:35:07 -05:00
Ed Hennis 63b47914b8 Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  refactor: Rename `ripple` namespace to `xrpl` (5982)
  refactor: Move JobQueue and related classes into xrpl.core module (6121)
  refactor: Rename `rippled` binary to `xrpld` (5983)
2025-12-11 15:25:43 -05:00
Ed Hennis 9e02e5be2e Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-10 18:55:14 -05:00
Ed Hennis 093cd70fa1 Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-05 21:12:43 -05:00
Ed Hennis 376d65a483 Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-02 17:21:39 -05:00
Ed Hennis a0d9a2458e Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-01 14:40:15 -05:00
Ed Hennis 456f639cf7 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-28 15:46:19 -05:00
Ed Hennis 2c559ec2f3 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-27 01:48:33 -05:00
Ed Hennis 619c81f463 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-26 00:24:50 -05:00
Ed Hennis f1490df960 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-25 14:54:38 -05:00
Ed Hennis 7bdf74de98 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-24 21:48:42 -05:00
Ed Hennis 1743d6fb98 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-24 21:29:52 -05:00
Ed Hennis ca7a5bb926 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-21 12:47:28 -05:00
Ed Hennis ce8b1a3f1e Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-18 22:39:06 -05:00
Ed Hennis 486fa75a10 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-15 03:08:18 -05:00
Ed Hennis f8d68cd3d3 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-13 12:18:08 -05:00
Ed Hennis ef7a3f5606 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-12 13:59:45 -05:00
Ed Hennis 4f84ed7490 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-10 19:52:42 -05:00
Ed Hennis d534103131 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-10 15:34:55 -05:00
Ed Hennis 82dff3c2ce Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-08 22:49:26 -05:00
Ed Hennis 30d73eb5ba Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-06 23:50:23 -05:00
Ed Hennis 1b2754bac2 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-05 22:23:07 -05:00
Ed Hennis cf80cafc75 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-04 18:02:30 -05:00
Ed Hennis b8897d51de Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-03 18:03:56 -05:00
Ed Hennis 3ff25eeb65 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-03 12:41:48 -05:00
Ed Hennis 2bbfc4e786 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-31 13:51:15 -04:00
Ed Hennis 2b1eb052e6 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-31 12:51:24 -04:00
Ed Hennis 360e214e54 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-29 14:23:10 -04:00
Ed Hennis 2618afed94 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-29 13:42:21 -04:00
Ed Hennis 698ba2c788 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-29 12:54:16 -04:00
Ed Hennis b614e99588 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-28 17:38:21 -04:00
Ed Hennis fe8e4af2fa Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-26 19:12:33 -04:00
Ed Hennis 0a897f1528 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-23 13:24:25 -04:00
Ed Hennis cf8a3f5779 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-22 11:38:49 -04:00
Ed Hennis db39a39868 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-21 22:20:04 -04:00
Ed Hennis 37a03d28c2 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-17 18:21:36 -04:00
Ed Hennis 19d275425a Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-16 13:12:08 -04:00
Ed Hennis 88e9045602 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-16 10:48:43 -04:00
Ed Hennis 5adbc536b6 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-10 13:01:32 -04:00
Ed Hennis e27af94ba9 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-09 15:14:47 -04:00
Ed Hennis 43fe1e7e9c Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-08 14:21:34 -04:00
Ed Hennis f456a858c8 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-02 11:03:07 -04:00
Ed Hennis 084c3aa88e Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-01 18:10:57 -04:00
Ed Hennis 34f9b63921 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-01 13:14:22 -04:00
Ed Hennis bd3de79817 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-30 22:28:53 -04:00
Ed Hennis 304eee2259 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-29 18:34:43 -04:00
Ed Hennis 9e729b7f59 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-29 17:37:16 -04:00
Ed Hennis dd141468c4 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-29 13:32:03 -04:00
Ed Hennis 933147c21f Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-26 19:25:58 -04:00
Ed Hennis 9201a4f591 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-26 13:41:27 -04:00
Ed Hennis 5adb1e9b8b Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-26 12:09:09 -04:00
Ed Hennis 4df84d7988 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-25 13:27:09 -04:00
Bart cd87c0968b Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-24 09:35:19 +02:00
Ed Hennis 8a8e7c90bf Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-20 15:44:32 -04:00
Ed Hennis e806069065 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-18 14:08:23 -04:00
Ed Hennis ce948cbec0 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-18 12:26:34 -04:00
Ed Hennis 6ed34b3294 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-18 11:54:30 -04:00
Ed Hennis 7161a235ca Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-17 10:49:03 -04:00
Ed Hennis 71463810de Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-16 10:46:37 -04:00
Ed Hennis e997219a85 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-15 11:13:28 -04:00
Ed Hennis 895cc13fa6 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-11 10:33:14 -04:00
Ed Hennis 8d3c3ca29a Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-10 18:53:24 -04:00
Ed Hennis 9829553807 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-09 17:14:20 -04:00
Ed Hennis e551f9731a Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-08 11:41:46 -04:00
Ed Hennis fd827bf58b Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-05 17:44:06 -04:00
Ed Hennis 5a3baba34d Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 20:24:55 -04:00
Ed Hennis c78f5b160f Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 16:43:48 -04:00
Ed Hennis 485f78761a Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 12:26:55 -04:00
Ed Hennis 23cd2f7b21 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 10:14:10 -04:00
Ed Hennis 5753266c43 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-03 14:04:01 -04:00
Ed Hennis 4722d2607d Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-29 15:52:53 -04:00
Ed Hennis 85b5b4f855 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-29 10:42:50 -04:00
Ed Hennis a16f492f0f Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-28 18:17:26 -04:00
Ed Hennis 3633dc632c Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-27 11:14:59 -04:00
Ed Hennis b3b30c3a86 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-25 14:10:52 -04:00
Ed Hennis c78a7684f4 Remove trailing space 2025-08-25 14:09:57 -04:00
Ed Hennis cf83d92630 Merge remote-tracking branch 'upstream/develop' into ximinez/online-delete-gaps
* upstream/develop:
  chore: Remove codecov token check to support tokenless uploads on forks (5722)
  Set version to 2.6.0-rc3
  Revert "perf: Move mutex to the partition level (5486)"
  chore: Update clang-format and prettier with pre-commit (5709)
  fix(test): handle null metadata for unvalidated tx in Env::meta (5715)
  chore: Workaround for CI build errors on arm64 (5717)
  chore: Fix file formatting (5718)
  fix: Skip notify-clio when running in a fork, reorder config fields (5712)
  chore: Reverts formatting changes to external files, adds formatting changes to proto files (5711)
2025-08-25 14:05:49 -04:00
Ed Hennis a56b1274d8 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-21 11:38:54 -04:00
Ed Hennis ae4bdd0492 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-19 16:05:17 -04:00
Ed Hennis e90102dd3b Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-18 12:15:38 -04:00
Ed Hennis 71f0e8db3d Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-08 18:23:24 -04:00
Ed Hennis 638929373a Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-08 11:10:20 -04:00
Ed Hennis 8440654377 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-06 21:03:00 -04:00
Ed Hennis 9fa66c4741 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-05 21:16:44 -04:00
Ed Hennis 38a9235145 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-04 13:04:52 -04:00
Ed Hennis c7a3cc9108 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-29 20:33:29 -04:00
Ed Hennis 248337908d Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-29 11:54:16 -04:00
Ed Hennis 3d003619fd Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-28 20:57:13 -04:00
Ed Hennis f163dca12c Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-24 15:50:09 -04:00
Ed Hennis 6e0ce458e5 Revert "TEMP: Change some logging to fatal to diagnose CI failures"
This reverts commit 69cf18158b.
2025-07-22 19:41:02 -04:00
Ed Hennis 5fae8480f1 Revert "TEMP: Add logging to SHAMapStore test"
This reverts commit fe7d0798a7.
2025-07-22 19:40:58 -04:00
Ed Hennis e6587d374a fixup! Tweak SHAMapStore test timing more 2025-07-22 19:39:58 -04:00
Ed Hennis 376cc404e0 Tweak SHAMapStore test timing more 2025-07-22 18:44:07 -04:00
Ed Hennis 9898ca638f Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-22 14:09:33 -04:00
Ed Hennis 34b46d8f7c Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-21 18:20:41 -04:00
Ed Hennis fe7d0798a7 TEMP: Add logging to SHAMapStore test 2025-07-21 18:19:53 -04:00
Ed Hennis 0cecc09d71 Tweak timing of SHAMapStore test 2025-07-21 18:19:28 -04:00
Ed Hennis e091d55561 Try to fix timing of LedgerMaster test 2025-07-21 15:14:42 -04:00
Ed Hennis 69cf18158b TEMP: Change some logging to fatal to diagnose CI failures 2025-07-21 14:32:08 -04:00
Ed Hennis 6513c53817 Improve logging
- There's still a race condition in there
2025-07-21 14:30:49 -04:00
Ed Hennis e13baa58a5 Fix build errors 2025-07-21 13:31:09 -04:00
Ed Hennis 951056fe9b Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-18 18:33:10 -04:00
Ed Hennis 67700ea6bd Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-16 12:54:23 -04:00
Ed Hennis e5442cf3f1 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-15 19:36:25 -04:00
Ed Hennis da68076f04 Change default recovery wait time to 1s
See https://github.com/XRPLF/rippled/pull/5531#issuecomment-3058218837
2025-07-14 14:13:32 -04:00
Ed Hennis b24116a118 Improve locking, logging, and test output
- Add more info to the error message on some failed tests.
- Add logging details to SHAMapStoreImp
2025-07-14 14:13:27 -04:00
Ed Hennis f67398c6bf Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-11 19:27:31 -04:00
Ed Hennis 43d3eb1a24 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-10 21:25:22 -04:00
Ed Hennis 0993315ed5 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-10 12:30:18 -04:00
Ed Hennis 0bc383ada9 Fix build errors 2025-07-08 20:15:05 -04:00
Ed Hennis 1841ceca43 Add more logging to SHAMapStore rotation 2025-07-08 16:05:03 -04:00
Ed Hennis 2714cebabd Revert "TEMP: Change logging to show progress during unit test"
This reverts commit e184db4ce2.
2025-07-08 16:02:45 -04:00
Ed Hennis e184db4ce2 TEMP: Change logging to show progress during unit test 2025-07-08 16:02:19 -04:00
Ed Hennis ac6dc6943c Tweak when the starting range of ledger gap detection is set
- Add a test to exercise online delete ledger gap detection
2025-07-08 16:01:23 -04:00
Ed Hennis ddd53806df Add a test to exercise LedgerMaster::missingFromCompleteLedgerRange 2025-07-08 13:22:47 -04:00
Ed Hennis e629a1f70e Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-03 15:51:23 -04:00
Ed Hennis 68076d969c fixup! fixup! Pause online delete if there any any gaps in recent ledger history 2025-07-02 19:05:06 -04:00
Ed Hennis d3009d3e1c fixup! Pause online delete if there any any gaps in recent ledger history 2025-07-02 18:51:42 -04:00
Ed Hennis 54f7f3c894 Pause online delete if there any any gaps in recent ledger history 2025-07-02 18:45:48 -04:00
130 changed files with 2818 additions and 1501 deletions

No files matched your search

+2 -1
View File
@@ -1123,7 +1123,8 @@
# online deletion gives up on the current ledger and tries
# again later. Note this only affects situations that cause
# rotation to wait, such as going out of sync, or missing
# ledgers. Forward progress is not penalized. Minimum is 64.
# ledgers. Forward progress is not penalized. Minimum in
# normal operation is 64. Minimum in standalone mode is 2.
# Default is the online_delete value.
#
# Notes:
-200
View File
@@ -1,200 +0,0 @@
#pragma once
#include <concepts>
#include <type_traits>
#include <utility>
namespace xrpl {
/**
* Opt-in bitwise operators for scoped enumerations.
*
* Provides `&`, `|`, `^`, `~` and the corresponding compound assignment forms
* for any scoped enumeration with an unsigned underlying type that opts in by
* specializing @ref OptIn:
*
* @code
* namespace xrpl {
*
* enum class MyFlags : std::uint32_t { a = 1, b = 2, c = 4 };
*
* template <>
* struct enum_bitops::OptIn<MyFlags> : std::true_type {};
*
* } // namespace xrpl
* @endcode
*
* The operators are constexpr and noexcept, and return the enumeration type.
*
* @par Where the specialization may be declared
* In namespace xrpl, or at global scope with full qualification, and after
* the enumeration is defined but before the operators are first used. This
* cannot be done in a nested namespace or at class scope; for enumerations
* nested in a class this means after the class definition.
*
* @par Where the operators are found
* The operators are declared in namespace xrpl, so argument-dependent lookup
* will find them only for enumerations declared in xrpl or nested in a class
* declared directly in xrpl. Enumerations in a nested namespace will only be
* found from code inside xrpl, and only if no enclosing scope declares an
* operator of the same name; elsewhere they require using-declarations.
*/
namespace enum_bitops {
/**
* Types that may be opted in to the bitwise operators.
*
* Satisfied by a scoped enumeration whose underlying type is an unsigned
* integer type.
*
* @tparam T The type to test.
*/
template <typename T>
concept Eligible = std::is_scoped_enum_v<T> && std::unsigned_integral<std::underlying_type_t<T>>;
/**
* Opt-in switch for the bitwise operators.
*
* The primary template derives from std::false_type. Specialize it to derive
* from std::true_type to enable the operators for an @ref Eligible enumeration.
*
* @tparam T The scoped enumeration to opt in.
*/
template <Eligible T>
struct OptIn : std::false_type
{
};
/**
* Enumerations for which the bitwise operators are enabled.
*
* Satisfied when @p T satisfies @ref Eligible and @ref OptIn has been
* specialized for it to derive from std::true_type.
*
* @tparam T The type to test.
*/
template <typename T>
concept Candidate = Eligible<T> && OptIn<T>::value;
} // namespace enum_bitops
// These are declared in xrpl, not in enum_bitops, so that argument-dependent
// lookup finds them for enumerations whose associated namespace is xrpl.
/**
* @name Bitwise operators for opted-in scoped enumerations
*
* Each operator applies the corresponding built-in operator to the
* underlying values and converts the result back to the enumeration type.
* Both operands must have the same enumeration type; there is no implicit
* conversion to or from the underlying type.
*/
/** @{ */
/**
* Bitwise AND.
*
* @param lhs The left operand.
* @param rhs The right operand.
* @return The bits set in both @p lhs and @p rhs.
*/
template <enum_bitops::Candidate T>
constexpr T
operator&(T lhs, T rhs) noexcept
{
return static_cast<T>(std::to_underlying(lhs) & std::to_underlying(rhs));
}
/**
* Bitwise OR.
*
* @param lhs The left operand.
* @param rhs The right operand.
* @return The bits set in @p lhs, in @p rhs, or in both.
*/
template <enum_bitops::Candidate T>
constexpr T
operator|(T lhs, T rhs) noexcept
{
return static_cast<T>(std::to_underlying(lhs) | std::to_underlying(rhs));
}
/**
* Bitwise exclusive OR.
*
* @param lhs The left operand.
* @param rhs The right operand.
* @return The bits set in exactly one of @p lhs and @p rhs.
*/
template <enum_bitops::Candidate T>
constexpr T
operator^(T lhs, T rhs) noexcept
{
return static_cast<T>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
}
/**
* Bitwise complement.
*
* The result has every bit of the underlying type that is clear in
* @p val, including bits that no enumerator names. It is intended for
* clearing flags, as in `flags & ~flag`.
*
* @param val The operand.
* @return The complement of @p val.
*/
template <enum_bitops::Candidate T>
constexpr T
operator~(T val) noexcept
{
return static_cast<T>(~std::to_underlying(val));
}
/**
* Bitwise AND assignment.
*
* @param lhs The value to modify.
* @param rhs The right operand.
* @return A reference to @p lhs.
*/
template <enum_bitops::Candidate T>
constexpr T&
operator&=(T& lhs, T rhs) noexcept
{
lhs = lhs & rhs;
return lhs;
}
/**
* Bitwise OR assignment.
*
* @param lhs The value to modify.
* @param rhs The right operand.
* @return A reference to @p lhs.
*/
template <enum_bitops::Candidate T>
constexpr T&
operator|=(T& lhs, T rhs) noexcept
{
lhs = lhs | rhs;
return lhs;
}
/**
* Bitwise exclusive OR assignment.
*
* @param lhs The value to modify.
* @param rhs The right operand.
* @return A reference to @p lhs.
*/
template <enum_bitops::Candidate T>
constexpr T&
operator^=(T& lhs, T rhs) noexcept
{
lhs = lhs ^ rhs;
return lhs;
}
/** @} */
} // namespace xrpl
+53 -12
View File
@@ -1,7 +1,7 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/enum_bitops.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/OwnerCounts.h>
#include <xrpl/ledger/ReadView.h>
@@ -22,39 +22,80 @@
namespace xrpl {
enum class ApplyFlags : std::uint32_t {
None = 0x00,
// Bitwise flag enum with existing operator overloads
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum ApplyFlags : std::uint32_t {
TapNone = 0x00,
// This is a local transaction with the
// fail_hard flag set.
FailHard = 0x10,
TapFailHard = 0x10,
// This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
Retry = 0x20,
TapRetry = 0x20,
// Transaction came from a privileged source
Unlimited = 0x400,
TapUnlimited = 0x400,
// Transaction is executing as part of a batch
Batch = 0x800,
TapBatch = 0x800,
// Transaction shouldn't be applied
// Signatures shouldn't be checked
DryRun = 0x1000,
TapDryRun = 0x1000,
// Transaction is being preflighted as the payload of a
// TransactionProposalCreate. Its signatures are collected on-ledger
// afterward, so signature-presence checks (e.g. Batch signer matching)
// are skipped at proposal-creation time (On-Chain Cosigner spec
// §5.3.1.2).
Proposal = 0x2000,
TapProposal = 0x2000,
};
template <>
struct enum_bitops::OptIn<ApplyFlags> : std::true_type
constexpr ApplyFlags
operator|(ApplyFlags const& lhs, ApplyFlags const& rhs)
{
};
return safeCast<ApplyFlags>(
safeCast<std::underlying_type_t<ApplyFlags>>(lhs) |
safeCast<std::underlying_type_t<ApplyFlags>>(rhs));
}
static_assert((TapFailHard | TapRetry) == safeCast<ApplyFlags>(0x30u), "ApplyFlags operator |");
static_assert((TapRetry | TapFailHard) == safeCast<ApplyFlags>(0x30u), "ApplyFlags operator |");
constexpr ApplyFlags
operator&(ApplyFlags const& lhs, ApplyFlags const& rhs)
{
return safeCast<ApplyFlags>(
safeCast<std::underlying_type_t<ApplyFlags>>(lhs) &
safeCast<std::underlying_type_t<ApplyFlags>>(rhs));
}
static_assert((TapFailHard & TapRetry) == TapNone, "ApplyFlags operator &");
static_assert((TapRetry & TapFailHard) == TapNone, "ApplyFlags operator &");
constexpr ApplyFlags
operator~(ApplyFlags const& flags)
{
return safeCast<ApplyFlags>(~safeCast<std::underlying_type_t<ApplyFlags>>(flags));
}
static_assert(~TapRetry == safeCast<ApplyFlags>(0xFFFFFFDFu), "ApplyFlags operator ~");
inline ApplyFlags
operator|=(ApplyFlags& lhs, ApplyFlags const& rhs)
{
lhs = lhs | rhs;
return lhs;
}
inline ApplyFlags
operator&=(ApplyFlags& lhs, ApplyFlags const& rhs)
{
lhs = lhs & rhs;
return lhs;
}
//------------------------------------------------------------------------------
@@ -5,6 +5,7 @@
#include <xrpl/nodestore/Database.h>
#include <xrpl/nodestore/Scheduler.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
@@ -54,6 +55,12 @@ public:
*/
virtual void
setRotationInFlight(bool inFlight) = 0;
virtual bool
isRotationInFlight() const = 0;
[[nodiscard]]
virtual std::uint64_t
getAndResetDuplicationCount() = 0;
};
} // namespace xrpl::node_store
@@ -72,19 +72,28 @@ public:
void
setRotationInFlight(bool inFlight) override;
bool
isRotationInFlight() const override;
[[nodiscard]]
std::uint64_t
getAndResetDuplicationCount() override;
private:
std::shared_ptr<Backend> writableBackend_;
std::shared_ptr<Backend> archiveBackend_;
mutable std::mutex mutex_;
// True between SHAMapStore starting the cache-freshen phase and the
// completion of rotate(). While true, archive hits on ordinary
// (duplicate == false) fetches are copied forward into the writable
// backend; copyForwardCount_ tallies them per rotation for the
// Set to true during the entire SHAMapStore rotation process.
// While true, archive hits on ordinary (duplicate == false)
// fetches are copied forward into the writable backend.
// copyForwardCount_ tallies them per rotation for the
// summary line logged at swap.
std::atomic<bool> rotationInFlight_{false};
std::atomic<std::uint64_t> copyForwardCount_{0};
// Duplication count tracks the number of nodes that are directly duplicated because they're in
// the target ledger or rescued from a cache.
std::atomic<std::uint64_t> duplicationCount_{0};
std::shared_ptr<NodeObject>
fetchNodeObject(UInt256 const& hash, std::uint32_t, FetchReport& fetchReport, bool duplicate)
+107 -80
View File
@@ -2,8 +2,6 @@
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/enum_bitops.h>
#include <xrpl/beast/hash/hash_append.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/AccountID.h>
@@ -17,43 +15,37 @@
#include <cstdint>
#include <memory>
#include <optional>
#include <type_traits>
#include <utility>
#include <vector>
namespace xrpl {
enum class STPathElementType : std::uint8_t {
// clang-format off
None = 0x00, ///< No element; also terminates the serialized path set.
Account = 0x01, ///< Rippling through an account (vs taking an offer).
Currency = 0x10, ///< Currency follows.
Issuer = 0x20, ///< Issuer follows.
Mpt = 0x40, ///< MPT follows.
Boundary = 0xFF, ///< Boundary between alternate paths.
Asset = Currency | Mpt, ///< Either asset kind.
All = Account | Currency | Issuer | Mpt, ///< Every value-carrying bit.
// clang-format on
};
template <>
struct enum_bitops::OptIn<STPathElementType> : std::true_type
{
};
class STPathElement final : public CountedObject<STPathElement>
{
STPathElementType type_ = STPathElementType::None;
bool isOffer_ = true;
unsigned int type_;
AccountID accountID_;
PathAsset assetID_;
AccountID issuerID_;
bool isOffer_;
std::size_t hashValue_;
public:
STPathElement() = default;
// Bitwise values (typeCurrency | typeMPT)
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum Type {
TypeNone = 0x00,
TypeAccount = 0x01, // Rippling through an account (vs taking an offer).
TypeCurrency = 0x10, // Currency follows.
TypeIssuer = 0x20, // Issuer follows.
TypeMpt = 0x40, // MPT follows.
TypeBoundary = 0xFF, // Boundary between alternate paths.
TypeAsset = TypeCurrency | TypeMpt,
TypeAll = TypeAccount | TypeCurrency | TypeIssuer | TypeMpt,
// Combination of all types.
};
STPathElement();
STPathElement(STPathElement const&) = default;
STPathElement&
operator=(STPathElement const&) = default;
@@ -70,42 +62,42 @@ public:
bool forceAsset = false);
STPathElement(
STPathElementType type,
unsigned int uType,
AccountID const& account,
PathAsset const& asset,
AccountID const& issuer);
[[nodiscard]] STPathElementType
getNodeType() const noexcept;
[[nodiscard]] std::uint32_t
getNodeType() const;
[[nodiscard]] bool
isOffer() const noexcept;
isOffer() const;
[[nodiscard]] bool
isAccount() const noexcept;
isAccount() const;
[[nodiscard]] bool
hasIssuer() const noexcept;
hasIssuer() const;
[[nodiscard]] bool
hasCurrency() const noexcept;
hasCurrency() const;
[[nodiscard]] bool
hasMPT() const noexcept;
hasMPT() const;
[[nodiscard]] bool
hasAsset() const noexcept;
hasAsset() const;
[[nodiscard]] bool
isNone() const noexcept;
isNone() const;
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a
// class of offers.
[[nodiscard]] AccountID const&
getAccountID() const noexcept;
getAccountID() const;
[[nodiscard]] PathAsset const&
getPathAsset() const noexcept;
getPathAsset() const;
[[nodiscard]] Currency const&
getCurrency() const;
@@ -114,18 +106,17 @@ public:
getMPTID() const;
[[nodiscard]] AccountID const&
getIssuerID() const noexcept;
getIssuerID() const;
[[nodiscard]] bool
isType(STPathElementType pe) const noexcept;
isType(Type const& pe) const;
friend bool
operator==(STPathElement const& lhs, STPathElement const& rhs) noexcept
{
return lhs.isType(STPathElementType::Account) == rhs.isType(STPathElementType::Account) &&
lhs.accountID_ == rhs.accountID_ && lhs.assetID_ == rhs.assetID_ &&
lhs.issuerID_ == rhs.issuerID_;
}
bool
operator==(STPathElement const& t) const;
private:
static std::size_t
getHash(STPathElement const& element);
};
template <class Hasher>
@@ -133,7 +124,7 @@ void
hash_append(Hasher& h, STPathElement const& e) noexcept
{
using beast::hash_append;
hash_append(h, e.isType(STPathElementType::Account));
hash_append(h, (e.getNodeType() & STPathElement::TypeAccount) != 0u);
hash_append(h, e.getAccountID());
hash_append(h, e.getPathAsset());
hash_append(h, e.getIssuerID());
@@ -346,16 +337,29 @@ private:
// ------------ STPathElement ------------
inline STPathElement::STPathElement() : type_(TypeNone), isOffer_(true)
{
// hashValue_ is derived from the whole object, so it is computed in the body
// once every other member is initialized (as in the other constructors).
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
hashValue_ = getHash(*this);
}
inline STPathElement::STPathElement(
std::optional<AccountID> const& account,
std::optional<PathAsset> const& asset,
std::optional<AccountID> const& issuer)
: type_(TypeNone)
{
if (account)
if (!account)
{
isOffer_ = true;
}
else
{
isOffer_ = false;
accountID_ = *account;
type_ |= STPathElementType::Account;
type_ |= TypeAccount;
XRPL_ASSERT(
accountID_ != noAccount(), "xrpl::STPathElement::STPathElement : account is set");
}
@@ -363,15 +367,17 @@ inline STPathElement::STPathElement(
if (asset)
{
assetID_ = *asset;
type_ |= assetID_.holds<Currency>() ? STPathElementType::Currency : STPathElementType::Mpt;
type_ |= assetID_.holds<Currency>() ? TypeCurrency : TypeMpt;
}
if (issuer)
{
issuerID_ = *issuer;
type_ |= STPathElementType::Issuer;
type_ |= TypeIssuer;
XRPL_ASSERT(issuerID_ != noAccount(), "xrpl::STPathElement::STPathElement : issuer is set");
}
hashValue_ = getHash(*this);
}
inline STPathElement::STPathElement(
@@ -379,94 +385,108 @@ inline STPathElement::STPathElement(
PathAsset const& asset,
AccountID const& issuer,
bool forceAsset)
: isOffer_(isXRP(account)), accountID_(account), assetID_(asset), issuerID_(issuer)
: type_(TypeNone)
, accountID_(account)
, assetID_(asset)
, issuerID_(issuer)
, isOffer_(isXRP(accountID_))
{
if (!isOffer_)
type_ |= STPathElementType::Account;
type_ |= TypeAccount;
if (forceAsset || !isXRP(assetID_))
type_ |= asset.holds<Currency>() ? STPathElementType::Currency : STPathElementType::Mpt;
type_ |= asset.holds<Currency>() ? TypeCurrency : TypeMpt;
if (!isXRP(issuer))
type_ |= STPathElementType::Issuer;
type_ |= TypeIssuer;
hashValue_ = getHash(*this);
}
inline STPathElement::STPathElement(
STPathElementType type,
unsigned int uType,
AccountID const& account,
PathAsset const& asset,
AccountID const& issuer)
: type_(type), isOffer_(isXRP(account)), accountID_(account), assetID_(asset), issuerID_(issuer)
: type_(uType)
, accountID_(account)
, assetID_(asset)
, issuerID_(issuer)
, isOffer_(isXRP(accountID_))
{
assetID_.visit(
[&](Currency const&) { type_ &= ~STPathElementType::Mpt; },
[&](MPTID const&) { type_ &= ~STPathElementType::Currency; });
[&](Currency const&) { type_ = type_ & (~Type::TypeMpt); },
[&](MPTID const&) { type_ = type_ & (~Type::TypeCurrency); });
// hashValue_ must be computed after type_ is adjusted above, so this cannot
// be a member initializer.
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
hashValue_ = getHash(*this);
}
inline STPathElementType
STPathElement::getNodeType() const noexcept
inline std::uint32_t
STPathElement::getNodeType() const
{
return type_;
}
inline bool
STPathElement::isOffer() const noexcept
STPathElement::isOffer() const
{
return isOffer_;
}
inline bool
STPathElement::isAccount() const noexcept
STPathElement::isAccount() const
{
return !isOffer();
}
inline bool
STPathElement::isType(STPathElementType pe) const noexcept
STPathElement::isType(Type const& pe) const
{
return (type_ & pe) != STPathElementType::None;
return (type_ & pe) != 0u;
}
inline bool
STPathElement::hasIssuer() const noexcept
STPathElement::hasIssuer() const
{
return isType(STPathElementType::Issuer);
return isType(STPathElement::TypeIssuer);
}
inline bool
STPathElement::hasCurrency() const noexcept
STPathElement::hasCurrency() const
{
return isType(STPathElementType::Currency);
return isType(STPathElement::TypeCurrency);
}
inline bool
STPathElement::hasMPT() const noexcept
STPathElement::hasMPT() const
{
return isType(STPathElementType::Mpt);
return isType(STPathElement::TypeMpt);
}
inline bool
STPathElement::hasAsset() const noexcept
STPathElement::hasAsset() const
{
return isType(STPathElementType::Asset);
return isType(STPathElement::TypeAsset);
}
inline bool
STPathElement::isNone() const noexcept
STPathElement::isNone() const
{
return getNodeType() == STPathElementType::None;
return getNodeType() == STPathElement::TypeNone;
}
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a
// class of offers.
inline AccountID const&
STPathElement::getAccountID() const noexcept
STPathElement::getAccountID() const
{
return accountID_;
}
inline PathAsset const&
STPathElement::getPathAsset() const noexcept
STPathElement::getPathAsset() const
{
return assetID_;
}
@@ -484,11 +504,18 @@ STPathElement::getMPTID() const
}
inline AccountID const&
STPathElement::getIssuerID() const noexcept
STPathElement::getIssuerID() const
{
return issuerID_;
}
inline bool
STPathElement::operator==(STPathElement const& t) const
{
return (type_ & TypeAccount) == (t.type_ & TypeAccount) && hashValue_ == t.hashValue_ &&
accountID_ == t.accountID_ && assetID_ == t.assetID_ && issuerID_ == t.issuerID_;
}
// ------------ STPath ------------
inline STPath::STPath(std::vector<STPathElement> p) : path_(std::move(p))
+1 -2
View File
@@ -51,8 +51,7 @@ public:
beast::Journal journal = beast::Journal{beast::Journal::getNullSink()})
: ApplyContext(registry, base, std::nullopt, tx, preclaimResult, baseFee, flags, journal)
{
XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
}
std::reference_wrapper<ServiceRegistry> registry;
+8 -11
View File
@@ -59,11 +59,10 @@ public:
, parentBatchId(parentBatchId)
, j(j)
{
XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::Batch, "Batch apply flag should be set");
XRPL_ASSERT((flags & TapBatch) == TapBatch, "Batch apply flag should be set");
XRPL_ASSERT_IF(
(flags & ApplyFlags::Proposal) != ApplyFlags::None,
(flags & ApplyFlags::DryRun) != ApplyFlags::None,
(flags & TapProposal) != TapNone,
(flags & TapDryRun) != TapNone,
"xrpl::PreflightContext : proposal preflight implies dry run");
}
@@ -75,11 +74,10 @@ public:
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: registry(registry), tx(tx), rules(std::move(rules)), flags(flags), j(j)
{
XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
XRPL_ASSERT_IF(
(flags & ApplyFlags::Proposal) != ApplyFlags::None,
(flags & ApplyFlags::DryRun) != ApplyFlags::None,
(flags & TapProposal) != TapNone,
(flags & TapDryRun) != TapNone,
"xrpl::PreflightContext : proposal preflight implies dry run");
}
@@ -118,7 +116,7 @@ public:
, j(j)
{
XRPL_ASSERT(
parentBatchId.has_value() == ((flags & ApplyFlags::Batch) == ApplyFlags::Batch),
parentBatchId.has_value() == ((flags & TapBatch) == TapBatch),
"Parent Batch ID should be set if batch apply flag is set");
}
@@ -131,8 +129,7 @@ public:
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: PreclaimContext(registry, view, preflightResult, tx, flags, std::nullopt, j)
{
XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set");
}
PreclaimContext&
+1 -1
View File
@@ -41,7 +41,7 @@ struct ApplyResult
inline bool
isTecClaimHardFail(TER ter, ApplyFlags flags)
{
return isTecClaim(ter) && ((flags & ApplyFlags::Retry) == ApplyFlags::None);
return isTecClaim(ter) && ((flags & TapRetry) == 0u);
}
/**
+45 -13
View File
@@ -54,6 +54,7 @@ DatabaseRotatingImp::rotate(
// deleted.
std::shared_ptr<node_store::Backend> oldArchiveBackend;
std::uint64_t copyForwards = 0;
std::uint64_t duplications = 0;
{
std::scoped_lock const lock(mutex_);
@@ -66,6 +67,7 @@ DatabaseRotatingImp::rotate(
writableBackend_ = std::move(newBackend);
copyForwards = copyForwardCount_.exchange(0, std::memory_order_relaxed);
duplications = duplicationCount_.exchange(0, std::memory_order_relaxed);
}
if (copyForwards > 0)
@@ -74,6 +76,11 @@ DatabaseRotatingImp::rotate(
<< " archive-served reads into the writable backend "
"during the rotation window";
}
if (duplications > 0)
{
JLOG(j_.warn()) << "Rotating: duplicated " << duplications
<< " nodes into the writable backend for the relevant cache.";
}
f(newWritableBackendName, newArchiveBackendName);
}
@@ -86,6 +93,22 @@ DatabaseRotatingImp::setRotationInFlight(bool inFlight)
<< (inFlight ? "enabled" : "disabled");
}
bool
DatabaseRotatingImp::isRotationInFlight() const
{
return rotationInFlight_.load(std::memory_order_acquire);
}
[[nodiscard]]
std::uint64_t
DatabaseRotatingImp::getAndResetDuplicationCount()
{
std::uint64_t duplications = 0;
duplications = duplicationCount_.exchange(0, std::memory_order_relaxed);
return duplications;
}
std::string
DatabaseRotatingImp::getName() const
{
@@ -186,26 +209,35 @@ DatabaseRotatingImp::fetchNodeObject(
nodeObject = fetch(writable);
if (!nodeObject)
{
// While a rotation is in flight, ordinary (duplicate == false)
// reads served by the archive are copied forward too: the
// archive is about to be deleted, and a body canonicalized
// into the cache after the freshen getKeys() snapshot would
// otherwise survive only in RAM once the archive is dropped.
auto const inFlight = isRotationInFlight();
// Otherwise try to fetch from the archive backend
nodeObject = fetch(archive);
if (nodeObject)
{
{
// Refresh the writable backend pointer
std::scoped_lock const lock(mutex_);
writable = writableBackend_;
}
// Update writable backend with data from the archive backend.
// While a rotation is in flight, ordinary (duplicate == false)
// reads served by the archive are copied forward too: the
// archive is about to be deleted, and a body canonicalized
// into the cache after the freshen getKeys() snapshot would
// otherwise survive only in RAM once the archive is dropped.
if (duplicate || rotationInFlight_.load(std::memory_order_acquire))
// Check isRotationInFlight again, because it may have been set since the first check.
if (duplicate || inFlight || isRotationInFlight())
{
if (!duplicate)
{
// Refresh the writable backend pointer since we need to use it
std::scoped_lock const lock(mutex_);
writable = writableBackend_;
}
if (duplicate)
{
duplicationCount_.fetch_add(1, std::memory_order_relaxed);
}
else
{
copyForwardCount_.fetch_add(1, std::memory_order_relaxed);
}
writable->store(nodeObject);
}
}
+94 -61
View File
@@ -1,10 +1,11 @@
#include <xrpl/protocol/STPathSet.h>
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/AccountID.h>
@@ -16,9 +17,7 @@
#include <xrpl/protocol/jss.h>
#include <algorithm>
#include <concepts>
#include <cstdint>
#include <format>
#include <cstddef>
#include <memory>
#include <stdexcept>
#include <utility>
@@ -26,6 +25,41 @@
namespace xrpl {
std::size_t
STPathElement::getHash(STPathElement const& element)
{
std::size_t hashAccount = 2654435761;
std::size_t hashCurrency = 2654435761;
std::size_t hashIssuer = 2654435761;
// NIKB NOTE: This doesn't have to be a secure hash as speed is more
// important. We don't even really need to fully hash the whole
// base_uint here, as a few bytes would do for our use.
//
// The note above is only true because the result of this function reaches
// nothing but STPathElement::operator==, where it is a fast-reject
// prefilter ahead of the field comparisons that decide the answer. Do not
// use it to key a container.
for (auto const x : element.getAccountID())
hashAccount += (hashAccount * 257) ^ x;
// Check pathAsset type instead of element's type_
// In some cases type_ might be account but the asset
// is still set to either MPT or currency (see Pathfinder::addLink())
element.getPathAsset().visit(
[&](MPTID const& mpt) { hashCurrency += beast::Uhash<>{}(mpt); },
[&](Currency const& currency) {
for (auto const x : currency)
hashCurrency += (hashCurrency * 509) ^ x;
});
for (auto const x : element.getIssuerID())
hashIssuer += (hashIssuer * 911) ^ x;
return (hashAccount ^ hashCurrency ^ hashIssuer);
}
// For guidance on deciding which option to pursue:
// 1. Try to decrease the size of the STPathSet first. For instance, if a std::optional was
// injected into the type, could you get the same functionality using a std::unique_ptr instead?
@@ -74,57 +108,62 @@ STPathSet::operator=(STPathSet const& other)
STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name)
{
std::vector<STPathElement> path;
STPathElementType type = STPathElementType::None;
do
for (;;)
{
type = safeCast<STPathElementType>(sit.get8());
int const iType = sit.get8();
if (type == STPathElementType::None || type == STPathElementType::Boundary)
if (iType == STPathElement::TypeNone || iType == STPathElement::TypeBoundary)
{
if (path.empty())
Throw<std::runtime_error>("bad path element: empty path");
{
JLOG(debugLog().error()) << "Empty path in pathset";
Throw<std::runtime_error>("empty path");
}
// Move rather than converting the vector to an STPath by copy.
value_.emplace_back(std::move(path));
path.clear();
continue;
if (iType == STPathElement::TypeNone)
return;
}
else if ((iType & ~STPathElement::TypeAll) != 0)
{
JLOG(debugLog().error()) << "Bad path element " << iType << " in pathset";
Throw<std::runtime_error>("bad path element");
}
else
{
auto const hasAccount = (iType & STPathElement::TypeAccount) != 0u;
auto const hasCurrency = (iType & STPathElement::TypeCurrency) != 0u;
auto const hasIssuer = (iType & STPathElement::TypeIssuer) != 0u;
auto const hasMPT = (iType & STPathElement::TypeMpt) != 0u;
if ((type & ~STPathElementType::All) != STPathElementType::None)
Throw<std::runtime_error>(
std::format("bad path element: <{:#04x}>", std::to_underlying(type)));
AccountID account;
PathAsset asset;
AccountID issuer;
bool const hasAccount = (type & STPathElementType::Account) == STPathElementType::Account;
bool const hasCurrency =
(type & STPathElementType::Currency) == STPathElementType::Currency;
bool const hasMPT = (type & STPathElementType::Mpt) == STPathElementType::Mpt;
bool const hasIssuer = (type & STPathElementType::Issuer) == STPathElementType::Issuer;
if (hasAccount)
account = sit.get160();
if (hasCurrency && hasMPT)
Throw<std::runtime_error>("bad path element: MPT and Currency");
if (hasCurrency && hasMPT)
{
JLOG(debugLog().error()) << "Bad path element MPT and Currency in pathset";
Throw<std::runtime_error>("bad path element: MPT and Currency");
}
AccountID account;
PathAsset asset;
AccountID issuer;
if (hasCurrency)
asset = Currency::fromRaw(sit.get160());
if (hasAccount)
account = sit.get160();
if (hasMPT)
asset = sit.get192();
if (hasCurrency)
asset = Currency::fromRaw(sit.get160());
if (hasIssuer)
issuer = sit.get160();
if (hasMPT)
asset = sit.get192();
if (hasIssuer)
issuer = sit.get160();
path.emplace_back(account, asset, issuer, hasCurrency || hasMPT);
} while (type != STPathElementType::None);
path.emplace_back(account, asset, issuer, hasCurrency || hasMPT);
}
}
}
STBase*
@@ -178,22 +217,24 @@ STPath::getJson(JsonOptions) const
for (auto const& it : path_)
{
json::Value elem(json::ValueType::Object);
auto const iType = it.getNodeType();
elem[jss::type] = safeCast<std::uint32_t>(it.getNodeType());
elem[jss::type] = iType;
if (it.isType(STPathElementType::Account))
if ((iType & STPathElement::TypeAccount) != 0u)
elem[jss::account] = to_string(it.getAccountID());
XRPL_ASSERT(
!(it.hasCurrency() && it.hasMPT()),
((iType & STPathElement::TypeCurrency) == 0u) ||
((iType & STPathElement::TypeMpt) == 0u),
"xrpl::STPath::getJson : not type Currency and MPT");
if (it.hasCurrency())
if ((iType & STPathElement::TypeCurrency) != 0u)
elem[jss::currency] = to_string(it.getCurrency());
if (it.hasMPT())
if ((iType & STPathElement::TypeMpt) != 0u)
elem[jss::mpt_issuance_id] = to_string(it.getMPTID());
if (it.hasIssuer())
if ((iType & STPathElement::TypeIssuer) != 0u)
elem[jss::issuer] = to_string(it.getIssuerID());
ret.append(elem);
@@ -225,42 +266,34 @@ STPathSet::add(Serializer& s) const
XRPL_ASSERT(getFName().fieldType == STI_PATHSET, "xrpl::STPathSet::add : valid field type");
bool first = true;
// Workaround, since `Serializer` does not accept strongly-typed enums
// yet. When support is added, the static_assert will trigger, and the
// lambda can be removed entirely.
auto const toByte = [](std::same_as<STPathElementType> auto t) noexcept {
static_assert(
!requires(Serializer& ser) { ser.add8(t); },
"Serializer::add8 now accepts STPathElementType directly; remove toByte.");
return std::to_underlying(t);
};
for (auto const& spPath : value_)
{
if (!first)
s.add8(toByte(STPathElementType::Boundary));
s.add8(STPathElement::TypeBoundary);
for (auto const& speElement : spPath)
{
s.add8(toByte(speElement.getNodeType()));
int const iType = speElement.getNodeType();
if (speElement.isType(STPathElementType::Account))
s.add8(iType);
if ((iType & STPathElement::TypeAccount) != 0u)
s.addBitString(speElement.getAccountID());
if (speElement.hasMPT())
if ((iType & STPathElement::TypeMpt) != 0u)
s.addBitString(speElement.getMPTID());
if (speElement.hasCurrency())
if ((iType & STPathElement::TypeCurrency) != 0u)
s.addBitString(speElement.getCurrency());
if (speElement.hasIssuer())
if ((iType & STPathElement::TypeIssuer) != 0u)
s.addBitString(speElement.getIssuerID());
}
first = false;
}
s.add8(toByte(STPathElementType::None));
s.add8(STPathElement::TypeNone);
}
} // namespace xrpl
+3 -4
View File
@@ -38,7 +38,7 @@ ApplyContext::ApplyContext(
, parentBatchId_(parentBatchId)
{
XRPL_ASSERT(
parentBatchId.has_value() == ((flags_ & ApplyFlags::Batch) == ApplyFlags::Batch),
parentBatchId.has_value() == ((flags_ & TapBatch) == TapBatch),
"Parent Batch ID should be set if batch apply flag is set");
view_.emplace(&base_, flags_);
}
@@ -53,14 +53,13 @@ std::optional<TxMeta>
ApplyContext::apply(TER ter)
{
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
return view_->apply(
base_, tx, ter, parentBatchId_, (flags_ & ApplyFlags::DryRun) != ApplyFlags::None, journal);
return view_->apply(base_, tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal);
}
void
ApplyContext::addOrderBook(Book const& book)
{
if ((flags_ & ApplyFlags::DryRun) == ApplyFlags::None)
if ((flags_ & TapDryRun) == TapNone)
registry.get().getOrderBookDB().addOrderBook(book);
}
+7 -9
View File
@@ -135,7 +135,7 @@ preflightCheckSigningKey(STObject const& sigObject, beast::Journal j)
std::optional<NotTEC>
preflightCheckSimulateKeys(ApplyFlags flags, STObject const& sigObject, beast::Journal j)
{
if ((flags & ApplyFlags::DryRun) != ApplyFlags::None) // simulation
if ((flags & TapDryRun) != 0u) // simulation
{
std::optional<Slice> const signature = sigObject[~sfTxnSignature];
if (signature && !signature->empty())
@@ -510,8 +510,7 @@ Transactor::minimumFee(
Fees const& fees,
ApplyFlags flags)
{
return scaleFeeLoad(
baseFee, registry.getFeeTrack(), fees, (flags & ApplyFlags::Unlimited) != ApplyFlags::None);
return scaleFeeLoad(baseFee, registry.getFeeTrack(), fees, (flags & TapUnlimited) != 0u);
}
TER
@@ -522,7 +521,7 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
auto const feePaid = ctx.tx[sfFee].xrp();
if ((ctx.flags & ApplyFlags::Batch) != ApplyFlags::None)
if ((ctx.flags & TapBatch) != 0u)
{
if (feePaid == beast::kZero)
return tesSUCCESS;
@@ -985,8 +984,7 @@ Transactor::checkSign(
return tesSUCCESS;
}
if (((flags & ApplyFlags::DryRun) != ApplyFlags::None) && pkSigner.empty() &&
!sigObject.isFieldPresent(sfSigners))
if (((flags & TapDryRun) != 0u) && pkSigner.empty() && !sigObject.isFieldPresent(sfSigners))
{
// simulate: skip signature validation when neither SigningPubKey nor
// Signers are provided
@@ -1157,7 +1155,7 @@ Transactor::checkMultiSign(
}
XRPL_ASSERT(
(flags & ApplyFlags::DryRun) != ApplyFlags::None || !spk.empty(),
(flags & TapDryRun) || !spk.empty(),
"xrpl::Transactor::checkMultiSign : non-empty signer or "
"simulation");
AccountID const signingAcctIDFromPubKey =
@@ -1645,7 +1643,7 @@ Transactor::operator()()
if (ctx_.size() > kOversizeMetaDataCap)
result = tecOVERSIZE;
if (isTecClaim(result) && ((view().flags() & ApplyFlags::FailHard) != ApplyFlags::None))
if (isTecClaim(result) && ((view().flags() & TapFailHard) != 0u))
{
// If the TapFailHard flag is set, a tec result
// must not do anything
@@ -1725,7 +1723,7 @@ Transactor::operator()()
// Once we call apply, we will no longer be able to look at view()
metadata = ctx_.apply(result);
if ((ctx_.flags() & ApplyFlags::DryRun) != ApplyFlags::None)
if ((ctx_.flags() & TapDryRun) != 0u)
return logger(result, false, std::move(metadata));
return logger(result, canApply, std::move(metadata));
+2 -2
View File
@@ -215,7 +215,7 @@ applyBatchTransactions(
auto const applyOneTransaction = [&registry, &j, &parentBatchId, &batchView](STTx const& tx) {
OpenView perTxBatchView(kBatchView, batchView);
auto const ret = apply(registry, perTxBatchView, parentBatchId, tx, ApplyFlags::Batch, j);
auto const ret = apply(registry, perTxBatchView, parentBatchId, tx, TapBatch, j);
XRPL_ASSERT(
ret.applied == (isTesSuccess(ret.ter) || isTecClaim(ret.ter)),
"Inner transaction should not be applied");
@@ -274,7 +274,7 @@ applyTransaction(
{
// Returns false if the transaction has need not be retried.
if (retryAssured)
flags = flags | ApplyFlags::Retry;
flags = flags | TapRetry;
JLOG(j.debug()) << "TXN " << txn.getTransactionID() << (retryAssured ? "/retry" : "/final");
+2 -4
View File
@@ -348,8 +348,7 @@ preflight(
// builds; re-check the same invariant here so a release build can't
// silently skip a proposed transaction's signature-presence checks
// outside of a dry run.
if ((flags & ApplyFlags::Proposal) != ApplyFlags::None &&
(flags & ApplyFlags::DryRun) == ApplyFlags::None)
if ((flags & TapProposal) != TapNone && (flags & TapDryRun) == TapNone)
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "apply (preflight): TapProposal set without TapDryRun.";
@@ -380,8 +379,7 @@ preflight(
PreflightContext const pfCtx(registry, tx, parentBatchId, rules, flags, j);
// See the comment in the other preflight() overload above.
if ((flags & ApplyFlags::Proposal) != ApplyFlags::None &&
(flags & ApplyFlags::DryRun) == ApplyFlags::None)
if ((flags & TapProposal) != TapNone && (flags & TapDryRun) == TapNone)
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "apply (preflight): TapProposal set without TapDryRun.";
+1 -1
View File
@@ -1101,7 +1101,7 @@ std::optional<std::variant<Quality, AMMOffer<TIn, TOut>>>
BookStep<TIn, TOut, TDerived>::tip(ReadView const& view) const
{
// This can be simplified (and sped up) if directories are never empty.
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
BookTip bt(sb, book_);
auto const lobQuality = bt.step(j_) ? std::optional<Quality>(bt.quality()) : std::nullopt;
// Multi-path offer generates an offer with the quality
+32 -18
View File
@@ -57,8 +57,10 @@ checkNear(IOUAmount const& expected, IOUAmount const& actual)
static bool
isXRPAccount(STPathElement const& pe)
{
return pe.getNodeType() == STPathElementType::Account && isXRP(pe.getAccountID());
}
if (pe.getNodeType() != STPathElement::TypeAccount)
return false;
return isXRP(pe.getAccountID());
};
static std::pair<TER, std::unique_ptr<Step>>
toStep(
@@ -69,8 +71,11 @@ toStep(
{
auto& j = ctx.j;
if (ctx.isFirst && e1->isAccount() && e1->hasCurrency() && e1->getPathAsset().isXRP())
if (ctx.isFirst && e1->isAccount() &&
((e1->getNodeType() & STPathElement::TypeCurrency) != 0u) && e1->getPathAsset().isXRP())
{
return makeXrpEndpointStep(ctx, e1->getAccountID());
}
if (ctx.isLast && isXRPAccount(*e1) && e2->isAccount())
return makeXrpEndpointStep(ctx, e2->getAccountID());
@@ -112,9 +117,15 @@ toStep(
// LCOV_EXCL_STOP
}
XRPL_ASSERT(e2->hasAsset() || e2->hasIssuer(), "xrpl::toStep : currency or issuer");
PathAsset const outAsset = e2->hasAsset() ? e2->getPathAsset() : curAsset;
auto const outIssuer = e2->hasIssuer() ? e2->getIssuerID() : curAsset.getIssuer();
XRPL_ASSERT(
(e2->getNodeType() & STPathElement::TypeAsset) ||
(e2->getNodeType() & STPathElement::TypeIssuer),
"xrpl::toStep : currency or issuer");
PathAsset const outAsset =
((e2->getNodeType() & STPathElement::TypeAsset) != 0u) ? e2->getPathAsset() : curAsset;
auto const outIssuer = ((e2->getNodeType() & STPathElement::TypeIssuer) != 0u)
? e2->getIssuerID()
: curAsset.getIssuer();
if (isXRP(curAsset) && outAsset.isXRP())
{
@@ -186,15 +197,16 @@ toStrand(
for (std::size_t i = 0; i < path.size(); ++i)
{
auto const& pe = path[i];
auto const t = pe.getNodeType();
if ((pe.getNodeType() & ~STPathElementType::All) != STPathElementType::None || pe.isNone())
if (((t & ~STPathElement::TypeAll) != 0u) || (t == 0u))
return {temBAD_PATH, Strand{}};
bool const hasAccount = pe.isType(STPathElementType::Account);
bool const hasIssuer = pe.hasIssuer();
bool const hasCurrency = pe.hasCurrency();
bool const hasMPT = pe.hasMPT();
bool const hasAsset = pe.hasAsset();
bool const hasAccount = (t & STPathElement::TypeAccount) != 0u;
bool const hasIssuer = (t & STPathElement::TypeIssuer) != 0u;
bool const hasCurrency = (t & STPathElement::TypeCurrency) != 0u;
bool const hasMPT = (t & STPathElement::TypeMpt) != 0u;
bool const hasAsset = (t & STPathElement::TypeAsset) != 0u;
if (hasAccount && (hasIssuer || hasCurrency))
return {temBAD_PATH, Strand{}};
@@ -238,7 +250,9 @@ toStrand(
}();
// Currency or MPT
auto const hasAsset = [](STPathElement const& pe) { return pe.hasAsset(); };
auto const hasAsset = [](STPathElement const pe) {
return pe.getNodeType() & STPathElement::TypeAsset;
};
std::vector<STPathElement> normPath;
// reserve enough for the path, the implied source, destination,
@@ -249,10 +263,10 @@ toStrand(
// transaction, as defined by the transaction's Account field. The Asset
// is either SendMax or Deliver.
auto const t = [&] {
auto const t = STPathElementType::Account | STPathElementType::Issuer;
auto const t = STPathElement::TypeAccount | STPathElement::TypeIssuer;
return curAsset.visit(
[&](MPTIssue const&) { return t | STPathElementType::Mpt; },
[&](Issue const&) { return t | STPathElementType::Currency; });
[&](MPTIssue const&) { return t | STPathElement::TypeMpt; },
[&](Issue const&) { return t | STPathElement::TypeCurrency; });
}();
// If MPT then the issuer is the actual issuer, it is never the source
// account.
@@ -421,7 +435,7 @@ toStrand(
return {msr.first, Strand{}};
result.push_back(std::move(msr.second));
impliedPE.emplace(
STPathElementType::Account, curAsset.getIssuer(), xrpCurrency(), xrpAccount());
STPathElement::TypeAccount, curAsset.getIssuer(), xrpCurrency(), xrpAccount());
cur = &*impliedPE;
}
}
@@ -436,7 +450,7 @@ toStrand(
return {msr.first, Strand{}};
result.push_back(std::move(msr.second));
impliedPE.emplace(
STPathElementType::Account, curAsset.getIssuer(), xrpCurrency(), xrpAccount());
STPathElement::TypeAccount, curAsset.getIssuer(), xrpCurrency(), xrpAccount());
cur = &*impliedPE;
}
}
@@ -187,8 +187,7 @@ AccountSet::preclaim(PreclaimContext const& ctx)
if (!dirIsEmpty(ctx.view, keylet::ownerDir(id)))
{
JLOG(ctx.j.trace()) << "Retry: Owner directory not empty.";
return ((ctx.flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terOWNERS}
: TER{tecOWNERS};
return ((ctx.flags & TapRetry) != 0u) ? TER{terOWNERS} : TER{tecOWNERS};
}
}
@@ -297,8 +297,7 @@ OfferCreate::checkAcceptAsset(
JLOG(j.debug()) << "delay: can't receive IOUs from non-existent issuer: "
<< to_string(asset.getIssuer());
return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_ACCOUNT}
: TER{tecNO_ISSUER};
return ((flags & TapRetry) != 0u) ? TER{terNO_ACCOUNT} : TER{tecNO_ISSUER};
}
// An account cannot create a trustline to itself, so no line can exist
@@ -321,8 +320,7 @@ OfferCreate::checkAcceptAsset(
{
JLOG(j.debug()) << "delay: can't receive IOUs from issuer with "
"DisallowIncomingTrustline set";
return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_LINE}
: TER{tecNO_LINE};
return ((flags & TapRetry) != 0u) ? TER{terNO_LINE} : TER{tecNO_LINE};
}
}
@@ -330,8 +328,7 @@ OfferCreate::checkAcceptAsset(
{
if (!trustLine)
{
return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_LINE}
: TER{tecNO_LINE};
return ((flags & TapRetry) != 0u) ? TER{terNO_LINE} : TER{tecNO_LINE};
}
// Entries have a canonical representation, determined by a
@@ -347,8 +344,7 @@ OfferCreate::checkAcceptAsset(
JLOG(j.debug()) << "delay: can't receive IOUs from "
"issuer without auth.";
return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_AUTH}
: TER{tecNO_AUTH};
return ((flags & TapRetry) != 0u) ? TER{terNO_AUTH} : TER{tecNO_AUTH};
}
}
@@ -93,8 +93,7 @@ LoanSet::preflight(PreflightContext const& ctx)
// A proposed LoanSet is stored unsigned; its CounterpartySignature is
// collected on-ledger afterward, so its absence here is expected, not an
// error (On-Chain Cosigner spec §5.3.1.2).
if (!tx.isFlag(tfInnerBatchTxn) && !counterPartySig &&
(ctx.flags & ApplyFlags::Proposal) == ApplyFlags::None)
if (!tx.isFlag(tfInnerBatchTxn) && !counterPartySig && (ctx.flags & TapProposal) == 0)
{
JLOG(ctx.j.warn()) << "LoanSet transaction must have a CounterpartySignature.";
return temBAD_SIGNER;
@@ -54,8 +54,8 @@ TransactionProposalCreate::preflight(PreflightContext const& ctx)
try
{
STTx const stx{STObject{proposedTx}};
auto const inner = xrpl::preflight(
ctx.registry, ctx.rules, stx, ApplyFlags::DryRun | ApplyFlags::Proposal, ctx.j);
auto const inner =
xrpl::preflight(ctx.registry, ctx.rules, stx, TapDryRun | TapProposal, ctx.j);
if (!isTesSuccess(inner.ter))
{
JLOG(ctx.j.debug()) << "TransactionProposalCreate: proposed txn "
@@ -205,7 +205,7 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx)
// is collected on-ledger afterward, so its absence here is expected, not
// an error (On-Chain Cosigner spec §5.3.1.2).
if (isAccountReserveSponsorship && !ctx.tx.isFieldPresent(sfSponsorSignature) &&
(ctx.flags & ApplyFlags::Proposal) == ApplyFlags::None)
(ctx.flags & TapProposal) == 0)
{
JLOG(ctx.j.debug()) << "preflight: account sponsorship requires sfSponsorSignature";
return temMALFORMED;
+2 -3
View File
@@ -371,8 +371,7 @@ Batch::preflight(PreflightContext const& ctx)
// TapBatch — PreflightContext with a parentBatchId requires it.
// LoanSet already short-circuits on tfInnerBatchTxn; it is also in
// kDisabledTxTypes, so it never reaches this call.
ApplyFlags const innerFlags =
ApplyFlags::Batch | (ctx.flags & (ApplyFlags::Proposal | ApplyFlags::DryRun));
ApplyFlags const innerFlags = TapBatch | (ctx.flags & (TapProposal | TapDryRun));
if (auto const preflightResult =
xrpl::preflight(ctx.registry, ctx.rules, parentBatchId, stx, innerFlags, ctx.j);
!isTesSuccess(preflightResult.ter))
@@ -444,7 +443,7 @@ Batch::preflightSigValidated(PreflightContext const& ctx)
// A proposed Batch is stored unsigned; its BatchSigners are collected
// on-ledger afterward, so the signer-presence match belongs to submission
// time, not proposal creation (On-Chain Cosigner spec §5.3.1.2).
if ((ctx.flags & ApplyFlags::Proposal) != ApplyFlags::None)
if ((ctx.flags & TapProposal) != 0)
return tesSUCCESS;
auto const parentBatchId = ctx.tx.getTransactionID();
+3 -3
View File
@@ -1941,11 +1941,11 @@ private:
auto const flowResult = [&] {
STAmount const deliver(eth(51'000'000));
STAmount smax(btc(61'000'000));
PaymentSandbox sb(env.current().get(), ApplyFlags::None);
PaymentSandbox sb(env.current().get(), TapNone);
STPathSet paths;
auto const ipe = [](MPTTester const& iss) {
return STPathElement(
STPathElementType::Mpt | STPathElementType::Issuer,
STPathElement::TypeMpt | STPathElement::TypeIssuer,
xrpAccount(),
PathAsset{iss.issuanceID()},
iss.issuer());
@@ -1979,7 +1979,7 @@ private:
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty())
return false;
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
+3 -3
View File
@@ -2015,11 +2015,11 @@ private:
auto const flowResult = [&] {
STAmount const deliver(USD(51));
STAmount smax(BTC(61));
PaymentSandbox sb(env.current().get(), ApplyFlags::None);
PaymentSandbox sb(env.current().get(), TapNone);
STPathSet paths;
auto const ipe = [](Issue const& iss) {
return STPathElement(
STPathElementType::Currency | STPathElementType::Issuer,
STPathElement::TypeCurrency | STPathElement::TypeIssuer,
xrpAccount(),
iss.currency,
iss.account);
@@ -2053,7 +2053,7 @@ private:
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty())
return false;
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
+2 -2
View File
@@ -4207,7 +4207,7 @@ private:
auto const jtx = env.jt(tx, Seq(1), Fee(10));
env.app().config().features.erase(featureMPTokensV2);
PreflightContext const ctx(
env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal);
auto const pf = AMMBid::checkExtraFeatures(ctx);
BEAST_EXPECT(pf == false);
env.app().config().features.insert(featureMPTokensV2);
@@ -4219,7 +4219,7 @@ private:
jtx.jv["Asset2"].removeMember("mpt_issuance_id");
jtx.stx = env.ust(jtx);
PreflightContext const ctx(
env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal);
auto const pf = AMMBid::preflight(ctx);
BEAST_EXPECT(pf == temBAD_AMM_TOKENS);
}
+3 -3
View File
@@ -3194,7 +3194,7 @@ private:
auto const jtx = env.jt(tx, Seq(1), Fee(baseFee));
env.app().config().features.erase(featureAMM);
PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal);
auto const pf = Transactor::invokePreflight<AMMBid>(pfCtx);
BEAST_EXPECT(pf == temDISABLED);
env.app().config().features.insert(featureAMM);
@@ -3205,7 +3205,7 @@ private:
jtx.jv["TxnSignature"] = "deadbeef";
jtx.stx = env.ust(jtx);
PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal);
auto const pf = Transactor::invokePreflight<AMMBid>(pfCtx);
BEAST_EXPECT(!isTesSuccess(pf));
}
@@ -3216,7 +3216,7 @@ private:
jtx.jv["Asset2"].removeMember("issuer");
jtx.stx = env.ust(jtx);
PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal);
auto const pf = Transactor::invokePreflight<AMMBid>(pfCtx);
BEAST_EXPECT(pf == temBAD_AMM_TOKENS);
}
+19 -12
View File
@@ -32,6 +32,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -894,8 +895,9 @@ public:
auto const jNoCred = credentials::ledgerEntry(env, becky, carol, credType);
BEAST_EXPECT(
jNoCred.isObject() && jNoCred.isMember(jss::result) &&
jNoCred[jss::result].isMember(jss::error) &&
jNoCred[jss::result][jss::error] == "entryNotFound");
jNoCred[jss::result][jss::error] == "entryNotFound" &&
jNoCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jNoCred[jss::result][jss::error_message] == "Entry not found.");
}
testcase("Credentials that aren't required");
@@ -918,8 +920,9 @@ public:
BEAST_EXPECT(
jNoCred.isObject() && jNoCred.isMember(jss::result) &&
jNoCred[jss::result].isMember(jss::error) &&
jNoCred[jss::result][jss::error] == "entryNotFound");
jNoCred[jss::result][jss::error] == "entryNotFound" &&
jNoCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jNoCred[jss::result][jss::error_message] == "Entry not found.");
}
{
@@ -957,8 +960,9 @@ public:
BEAST_EXPECT(
jNoCred.isObject() && jNoCred.isMember(jss::result) &&
jNoCred[jss::result].isMember(jss::error) &&
jNoCred[jss::result][jss::error] == "entryNotFound");
jNoCred[jss::result][jss::error] == "entryNotFound" &&
jNoCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jNoCred[jss::result][jss::error_message] == "Entry not found.");
}
testcase("Expired credentials");
@@ -994,8 +998,9 @@ public:
auto jv = credentials::ledgerEntry(env, john, carol, credType);
BEAST_EXPECT(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
jv[jss::result][jss::error] == "entryNotFound");
jv[jss::result][jss::error] == "entryNotFound" &&
jv[jss::result][jss::error_code] == RpcEntryNotFound &&
jv[jss::result][jss::error_message] == "Entry not found.");
}
}
}
@@ -1079,8 +1084,9 @@ public:
auto const jv = credentials::ledgerEntry(env, becky, carol, credType);
BEAST_EXPECT(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
jv[jss::result][jss::error] == "entryNotFound");
jv[jss::result][jss::error] == "entryNotFound" &&
jv[jss::result][jss::error_code] == RpcEntryNotFound &&
jv[jss::result][jss::error_message] == "Entry not found.");
}
}
@@ -1121,8 +1127,9 @@ public:
auto const jv = credentials::ledgerEntry(env, becky, carol, credType);
BEAST_EXPECT(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
jv[jss::result][jss::error] == "entryNotFound");
jv[jss::result][jss::error] == "entryNotFound" &&
jv[jss::result][jss::error_code] == RpcEntryNotFound &&
jv[jss::result][jss::error_message] == "Entry not found.");
}
}
}
+1 -1
View File
@@ -597,7 +597,7 @@ public:
stx->at(sfSigningPubKey) = makeSlice(std::string("badkey"));
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, *stx, TapNone, j);
BEAST_EXPECT(result.ter == temBAD_SIGNATURE);
BEAST_EXPECT(!result.applied);
return result.applied;
+16 -13
View File
@@ -43,6 +43,7 @@
#include <xrpl/ledger/OpenView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Batch.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -432,7 +433,7 @@ class Batch_test : public beast::unit_test::Suite
{
auto const jtx = env.jt(pay(alice, bob, XRP(1)), Txflags(tfInnerBatchTxn));
PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal);
auto const pf = Transactor::invokePreflight<Payment>(pfCtx);
BEAST_EXPECT(pf == temINVALID_INNER_BATCH);
}
@@ -447,7 +448,7 @@ class Batch_test : public beast::unit_test::Suite
disabledEnv.app(),
*jtx.stx,
disabledEnv.current()->rules(),
ApplyFlags::None,
TapNone,
disabledEnv.journal);
auto const pf = Transactor::invokePreflight<Payment>(pfCtx);
BEAST_EXPECT(pf == temINVALID_FLAG);
@@ -458,12 +459,7 @@ class Batch_test : public beast::unit_test::Suite
{
auto const jtx = env.jt(pay(alice, bob, XRP(1)));
PreflightContext const pfCtx(
env.app(),
*jtx.stx,
UInt256{1},
env.current()->rules(),
ApplyFlags::Batch,
env.journal);
env.app(), *jtx.stx, UInt256{1}, env.current()->rules(), TapBatch, env.journal);
auto const pf = Transactor::invokePreflight<Payment>(pfCtx);
BEAST_EXPECT(pf == temINVALID_INNER_BATCH);
}
@@ -1601,7 +1597,7 @@ class Batch_test : public beast::unit_test::Suite
batch::Sig(std::vector<Reg>(kMaxBatchSigners + 1, bob)));
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *jt.stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, *jt.stx, TapNone, j);
BEAST_EXPECT(!result.applied && result.ter == temARRAY_TOO_LARGE);
return result.applied;
});
@@ -2805,6 +2801,7 @@ class Batch_test : public beast::unit_test::Suite
auto const jrr = env.rpc("submit", strHex(slice))[jss::result];
expect(
jrr[jss::status] == "error" && jrr[jss::error] == "invalidTransaction" &&
!jrr.isMember(jss::error_code) && jrr[jss::error_message].isNull() &&
jrr[jss::error_exception] ==
"fails local checks: Batch inner transactions are never "
"considered validly signed.",
@@ -4721,7 +4718,7 @@ class Batch_test : public beast::unit_test::Suite
BEAST_EXPECT(!passesLocalChecks(stx, reason));
BEAST_EXPECT(reason == "Cannot submit pseudo transactions.");
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, stx, TapNone, j);
BEAST_EXPECT(!result.applied && result.ter == temINVALID_FLAG);
return result.applied;
});
@@ -5412,7 +5409,10 @@ class Batch_test : public beast::unit_test::Suite
// The delegated payment never applied.
BEAST_EXPECT(env.balance(mallory) == preMallory);
BEAST_EXPECT(env.rpc("tx", txIDs[1])[jss::result][jss::error] == "txnNotFound");
auto const txResult = env.rpc("tx", txIDs[1])[jss::result];
BEAST_EXPECT(txResult[jss::error] == "txnNotFound");
BEAST_EXPECT(txResult[jss::error_code] == RpcTxnNotFound);
BEAST_EXPECT(txResult[jss::error_message] == "Transaction not found.");
}
}
@@ -5823,7 +5823,10 @@ class Batch_test : public beast::unit_test::Suite
validateClosedLedger(env, testCases);
// verify jv2 is not present in the closed ledger.
BEAST_EXPECT(env.rpc("tx", txIDs[1])[jss::result][jss::error] == "txnNotFound");
auto const txResult = env.rpc("tx", txIDs[1])[jss::result];
BEAST_EXPECT(txResult[jss::error] == "txnNotFound");
BEAST_EXPECT(txResult[jss::error_code] == RpcTxnNotFound);
BEAST_EXPECT(txResult[jss::error_message] == "Transaction not found.");
}
}
@@ -6021,7 +6024,7 @@ class Batch_test : public beast::unit_test::Suite
obj.setFieldU32(sfFlags, tfInnerBatchTxn);
});
auto const result = xrpl::apply(env.app(), view, stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, stx, TapNone, j);
// Must NOT be applied — signature was never checked
BEAST_EXPECT(!result.applied);
return false;
@@ -20,6 +20,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Protocol.h>
@@ -259,8 +260,9 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase
auto const credentialDeleted = [&](Env& env, Account const& subject) -> bool {
auto const credentials = credentials::ledgerEntry(env, subject, dpIssuer, credType);
return credentials[jss::result].isMember(jss::error) &&
credentials[jss::result][jss::error] == "entryNotFound";
return credentials[jss::result][jss::error] == "entryNotFound" &&
credentials[jss::result][jss::error_code] == RpcEntryNotFound &&
credentials[jss::result][jss::error_message] == "Entry not found.";
};
// TEST 4: Expired credential with matching depositPreauth entry.
+11 -2
View File
@@ -1748,8 +1748,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
(*sle)[sfConfidentialBalanceVersion] = wrappedFrom;
view.rawReplace(sle);
auto const result =
xrpl::apply(env.app(), view, *jt.stx, ApplyFlags::None, env.journal);
auto const result = xrpl::apply(env.app(), view, *jt.stx, TapNone, env.journal);
BEAST_EXPECT(result.ter == tesSUCCESS);
return result.applied;
}));
@@ -7945,6 +7944,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
// Signature verification fails — rejected before ZKP check
auto const jr = env.rpc("submit", strHex(tampered.slice()));
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
}
// Variant B: Re-signed with inflated ciphertext.
@@ -8052,6 +8053,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
auto const jr = env.rpc("submit", strHex(tampered.slice()));
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
}
// Variant B: Re-signed with all negated ciphertexts.
@@ -8155,6 +8158,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
auto const jr = env.rpc("submit", strHex(tampered.slice()));
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
}
// Variant B: Re-signed with combined ciphertext.
@@ -8279,6 +8284,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
// Signature verification fails
auto const jr = env.rpc("submit", strHex(tampered.slice()));
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
}
// Variant B: Re-signed C1 substitution.
@@ -8369,6 +8376,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
// signed — transaction rejected before ZKP verification.
auto const jr = env.rpc("submit", strHex(tampered.slice()));
BEAST_EXPECT(jr[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!jr[jss::result].isMember(jss::error_code));
BEAST_EXPECT(jr[jss::result][jss::error_message].isNull());
}
// -----------------------------------------------------------------
+36 -24
View File
@@ -23,6 +23,7 @@
#include <xrpl/ledger/ApplyViewImpl.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -124,8 +125,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
}
@@ -173,8 +175,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, issuer, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
}
}
@@ -222,8 +225,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
// resurrection
@@ -259,8 +263,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
// resurrection
@@ -294,8 +299,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
// resurrection
@@ -331,8 +337,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
// resurrection
@@ -368,8 +375,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
}
@@ -390,8 +398,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
}
@@ -410,8 +419,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jle = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jle.isObject() && jle.isMember(jss::result) &&
jle[jss::result].isMember(jss::error) &&
jle[jss::result][jss::error] == "entryNotFound");
jle[jss::result][jss::error] == "entryNotFound" &&
jle[jss::result][jss::error_code] == RpcEntryNotFound &&
jle[jss::result][jss::error_message] == "Entry not found.");
}
}
}
@@ -744,8 +754,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jDelCred = credentials::ledgerEntry(env, subject, issuer, credType2);
BEAST_EXPECT(
jDelCred.isObject() && jDelCred.isMember(jss::result) &&
jDelCred[jss::result].isMember(jss::error) &&
jDelCred[jss::result][jss::error] == "entryNotFound");
jDelCred[jss::result][jss::error] == "entryNotFound" &&
jDelCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jDelCred[jss::result][jss::error_message] == "Entry not found.");
BEAST_EXPECT(ownerCount(env, issuer) == 0);
BEAST_EXPECT(ownerCount(env, subject) == 1);
@@ -781,8 +792,9 @@ struct Credentials_test : public beast::unit_test::Suite
auto const jDelCred = credentials::ledgerEntry(env, subject, issuer, credType);
BEAST_EXPECT(
jDelCred.isObject() && jDelCred.isMember(jss::result) &&
jDelCred[jss::result].isMember(jss::error) &&
jDelCred[jss::result][jss::error] == "entryNotFound");
jDelCred[jss::result][jss::error] == "entryNotFound" &&
jDelCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jDelCred[jss::result][jss::error_message] == "Entry not found.");
}
}
}
@@ -909,7 +921,7 @@ struct Credentials_test : public beast::unit_test::Suite
{
testcase("deleteSLE fail, bad SLE.");
auto const view =
std::make_shared<ApplyViewImpl>(env.current().get(), ApplyFlags::None);
std::make_shared<ApplyViewImpl>(env.current().get(), ApplyFlags::TapNone);
auto const ter = xrpl::credentials::deleteSLE(*view, {}, env.journal);
BEAST_EXPECT(ter == tecNO_ENTRY);
}
@@ -1132,7 +1144,7 @@ struct Credentials_test : public beast::unit_test::Suite
// Create an ApplyViewImpl on top of the current closed ledger
// and corrupt it by erasing the issuer's account SLE
auto const open = env.current();
ApplyViewImpl av(&*open, ApplyFlags::None);
ApplyViewImpl av(&*open, TapNone);
// Erase the issuer's account to simulate ledger corruption
auto const sleIssuer = av.peek(keylet::account(issuer.id()));
+9 -2
View File
@@ -38,6 +38,7 @@
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/Dir.h>
#include <xrpl/ledger/helpers/DelegateHelpers.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -159,6 +160,8 @@ class Delegate_test : public beast::unit_test::Suite
env.close();
auto const jle = delegate::entry(env, gw, alice);
BEAST_EXPECT(jle[jss::result][jss::error] == "entryNotFound");
BEAST_EXPECT(jle[jss::result][jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jle[jss::result][jss::error_message] == "Entry not found.");
// alice can delegate permissions to gw as well
env(delegate::set(alice, gw, permissions));
@@ -167,6 +170,8 @@ class Delegate_test : public beast::unit_test::Suite
auto const response = delegate::entry(env, gw, alice);
// alice has not been granted any permissions by gw
BEAST_EXPECT(response[jss::result][jss::error] == "entryNotFound");
BEAST_EXPECT(response[jss::result][jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(response[jss::result][jss::error_message] == "Entry not found.");
}
void
@@ -2780,9 +2785,11 @@ class Delegate_test : public beast::unit_test::Suite
jv[jss::secret] = bob.name();
auto jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message].asString().contains(
"A Signer may not be the transaction's Account"));
jrr[jss::error_message] ==
"A Signer may not be the transaction's Account (" + bob.human() + ").");
}
}
+13 -8
View File
@@ -28,6 +28,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -1143,8 +1144,9 @@ struct DepositPreauth_test : public beast::unit_test::Suite
ledgerEntryDepositPreauth(env, bob, {{.issuer = issuer, .credType = credType}});
BEAST_EXPECT(
jDP.isObject() && jDP.isMember(jss::result) &&
jDP[jss::result].isMember(jss::error) &&
jDP[jss::result][jss::error] == "entryNotFound");
jDP[jss::result][jss::error] == "entryNotFound" &&
jDP[jss::result][jss::error_code] == RpcEntryNotFound &&
jDP[jss::result][jss::error_message] == "Entry not found.");
}
}
}
@@ -1232,8 +1234,9 @@ struct DepositPreauth_test : public beast::unit_test::Suite
auto const jDelCred = credentials::ledgerEntry(env, alice, issuer, credType);
BEAST_EXPECT(
jDelCred.isObject() && jDelCred.isMember(jss::result) &&
jDelCred[jss::result].isMember(jss::error) &&
jDelCred[jss::result][jss::error] == "entryNotFound");
jDelCred[jss::result][jss::error] == "entryNotFound" &&
jDelCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jDelCred[jss::result][jss::error_message] == "Entry not found.");
}
{
@@ -1283,8 +1286,9 @@ struct DepositPreauth_test : public beast::unit_test::Suite
auto const jDelCred = credentials::ledgerEntry(env, gw, issuer, credType);
BEAST_EXPECT(
jDelCred.isObject() && jDelCred.isMember(jss::result) &&
jDelCred[jss::result].isMember(jss::error) &&
jDelCred[jss::result][jss::error] == "entryNotFound");
jDelCred[jss::result][jss::error] == "entryNotFound" &&
jDelCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jDelCred[jss::result][jss::error_message] == "Entry not found.");
BEAST_EXPECT(ownerCount(env, issuer) == 0);
BEAST_EXPECT(ownerCount(env, gw) == 0);
@@ -1358,8 +1362,9 @@ struct DepositPreauth_test : public beast::unit_test::Suite
auto const jDelCred = credentials::ledgerEntry(env, zelda, issuer, credType);
BEAST_EXPECT(
jDelCred.isObject() && jDelCred.isMember(jss::result) &&
jDelCred[jss::result].isMember(jss::error) &&
jDelCred[jss::result][jss::error] == "entryNotFound");
jDelCred[jss::result][jss::error] == "entryNotFound" &&
jDelCred[jss::result][jss::error_code] == RpcEntryNotFound &&
jDelCred[jss::result][jss::error_message] == "Entry not found.");
}
}
+2 -2
View File
@@ -2773,7 +2773,7 @@ struct EscrowToken_test : public beast::unit_test::Suite
auto const seq1 = env.seq(alice);
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
auto const sleNew =
std::make_shared<SLE>(keylet::escrow(alice, SeqProxy::rawSequence(seq1)));
MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
@@ -3003,7 +3003,7 @@ struct EscrowToken_test : public beast::unit_test::Suite
auto const seq1 = env.seq(alice);
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
auto const sleNew =
std::make_shared<SLE>(keylet::escrow(alice, SeqProxy::rawSequence(seq1)));
MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
+8 -8
View File
@@ -1126,8 +1126,8 @@ struct Escrow_test : public beast::unit_test::Suite
env(jt, Ter(fixEnabled ? TER{temMALFORMED} : TER{tecCRYPTOCONDITION_ERROR}));
// Run preflight on the same transaction again, now with the
// HashRouter flag cached. The result must not change.
auto const pf = preflight(
env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal);
BEAST_EXPECT(pf.ter == (fixEnabled ? TER{temMALFORMED} : TER{tesSUCCESS}));
env.close();
@@ -1344,8 +1344,8 @@ struct Escrow_test : public beast::unit_test::Suite
escrow::kFinishTime(env.now() + 1s),
Seq(1),
Fee(baseFee));
auto const pf = preflight(
env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -1354,8 +1354,8 @@ struct Escrow_test : public beast::unit_test::Suite
{
auto const jtx = env.jt(escrow::cancel("bob", "alice", 3), Seq(1), Fee(baseFee));
auto const pf = preflight(
env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -1364,8 +1364,8 @@ struct Escrow_test : public beast::unit_test::Suite
{
auto const jtx = env.jt(escrow::finish("bob", "alice", 3), Seq(1), Fee(baseFee));
auto const pf = preflight(
env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
+3 -2
View File
@@ -160,7 +160,7 @@ createInvalidFeeTx(
TER
applyFeeAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx)
{
auto const res = apply(env.app(), view, tx, ApplyFlags::None, env.journal);
auto const res = apply(env.app(), view, tx, ApplyFlags::TapNone, env.journal);
return res.ter;
}
@@ -1473,7 +1473,8 @@ class FeeVote_test : public beast::unit_test::Suite
OpenView accum(ledger.get());
BEAST_EXPECT(!accum.open());
auto const result = apply(env.app(), accum, amendTx, ApplyFlags::None, env.journal);
auto const result =
apply(env.app(), accum, amendTx, ApplyFlags::TapNone, env.journal);
BEAST_EXPECTS(result.applied && isTesSuccess(result.ter), transToken(result.ter));
accum.apply(*ledger);
}
+3 -3
View File
@@ -338,11 +338,11 @@ struct FlowMPT_test : public beast::unit_test::Suite
auto const flowResult = [&] {
STAmount const deliver(usd(5'100));
STAmount smax(btc(61));
PaymentSandbox sb(env.current().get(), ApplyFlags::None);
PaymentSandbox sb(env.current().get(), TapNone);
STPathSet paths;
auto const ipe = [](Asset const& asset) {
return STPathElement(
STPathElementType::Asset | STPathElementType::Issuer,
STPathElement::TypeAsset | STPathElement::TypeIssuer,
xrpAccount(),
asset,
asset.getIssuer());
@@ -376,7 +376,7 @@ struct FlowMPT_test : public beast::unit_test::Suite
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty())
return false;
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
+3 -3
View File
@@ -476,11 +476,11 @@ struct Flow_test : public beast::unit_test::Suite
auto const flowResult = [&] {
STAmount const deliver(usd(51));
STAmount smax(btc(61));
PaymentSandbox sb(env.current().get(), ApplyFlags::None);
PaymentSandbox sb(env.current().get(), TapNone);
STPathSet paths;
auto const ipe = [](Issue const& iss) {
return STPathElement(
STPathElementType::Currency | STPathElementType::Issuer,
STPathElement::TypeCurrency | STPathElement::TypeIssuer,
xrpAccount(),
iss.currency,
iss.account);
@@ -514,7 +514,7 @@ struct Flow_test : public beast::unit_test::Suite
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty())
return false;
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
for (auto const& o : flowResult.removableOffers)
{
if (auto const ok = sb.peek(keylet::offer(o)))
+1 -1
View File
@@ -63,7 +63,7 @@ public:
if (stx)
{
OpenView accum(&*res);
applyTransaction(env.app(), accum, *stx, false, ApplyFlags::None, env.journal);
applyTransaction(env.app(), accum, *stx, false, TapNone, env.journal);
accum.apply(*res);
}
res->updateSkipList();
+2 -2
View File
@@ -90,7 +90,7 @@ struct LedgerReplay_test : public beast::unit_test::Suite
auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
auto const replayed = buildLedger(
LedgerReplay(lastClosedParent, lastClosed), ApplyFlags::None, env.app(), env.journal);
LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal);
BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
}
@@ -122,7 +122,7 @@ struct LedgerReplay_test : public beast::unit_test::Suite
auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
auto const replayed = buildLedger(
LedgerReplay(lastClosedParent, lastClosed), ApplyFlags::None, env.app(), env.journal);
LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal);
BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
}
+14 -1
View File
@@ -39,6 +39,7 @@
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/Indexes.h>
@@ -1020,6 +1021,7 @@ class MPToken_test : public beast::unit_test::Suite
payment[jss::build_path] = true;
auto jrr = env.rpc("json", "submit", to_string(payment));
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::result][jss::error_message] ==
"Field 'build_path' not allowed in this context.");
@@ -1581,6 +1583,8 @@ class MPToken_test : public beast::unit_test::Suite
jv[jss::tx_json][jss::Amount][jss::value] = std::to_string(kMaxMpTokenAmount + 1);
auto const jrr = env.rpc("json", "submit", to_string(jv));
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::result][jss::error_message] == "Invalid field 'tx_json.Amount'.");
}
// Pay maximum amount with the transfer fee, SendMax, and
@@ -1945,6 +1949,8 @@ class MPToken_test : public beast::unit_test::Suite
jtx.stx->add(s);
auto jrr = env.rpc("submit", strHex(s.slice()));
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!jrr[jss::result].isMember(jss::error_code));
BEAST_EXPECT(jrr[jss::result][jss::error_message].isNull());
// tx is unsigned
json::Value jv1;
@@ -1952,9 +1958,13 @@ class MPToken_test : public beast::unit_test::Suite
jv1[jss::tx_json] = jv;
jrr = env.rpc("json", "submit", to_string(jv1));
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::result][jss::error_message] == "Amount can not be MPT.");
jrr = env.rpc("json", "sign", to_string(jv1));
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::result][jss::error_message] == "Amount can not be MPT.");
};
auto setMPTFields = [&](SField const& field, json::Value& jv, bool withAmount = true) {
jv[jss::Asset] = toJson(xrpIssue());
@@ -3198,6 +3208,9 @@ class MPToken_test : public beast::unit_test::Suite
jv1[jss::tx_json] = jv;
auto const jrr = env.rpc("json", "submit", to_string(jv1));
BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::result][jss::error_message] == "Field 'tx_json.Amount' has invalid data.");
}
}
@@ -4118,7 +4131,7 @@ class MPToken_test : public beast::unit_test::Suite
TER expectedTer,
std::optional<std::uint64_t> expectedOutstanding,
std::string const& label) {
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
auto const ter =
accountSendMulti(av, issuer.id(), asset, receivers, env.app().getJournal("View"));
BEAST_EXPECTS(ter == expectedTer, label);
+44
View File
@@ -31,6 +31,7 @@
#include <xrpl/config/Constants.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/KeyType.h>
@@ -586,6 +587,7 @@ public:
auto jrr = env.rpc("json", "sign_for", to_string(jvOne))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message] ==
"When multi-signing 'tx_json.SigningPubKey' must be empty.");
@@ -613,6 +615,7 @@ public:
jrr = env.rpc("json", "submit_multisigned", to_string(jvSubmit))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid Fee field. Fees must be greater than zero.");
}
@@ -639,6 +642,7 @@ public:
jrr = env.rpc("json", "submit_multisigned", to_string(jvSubmit))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "internal");
BEAST_EXPECT(jrr[jss::error_code] == RpcInternal);
BEAST_EXPECT(jrr[jss::error_message] == "Internal error.");
}
@@ -651,6 +655,8 @@ public:
auto jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "masterDisabled");
BEAST_EXPECT(jrr[jss::error_code] == RpcMasterDisabled);
BEAST_EXPECT(jrr[jss::error_message] == "Master key is disabled.");
env.close();
BEAST_EXPECT(env.seq(alice) == aliceSeq);
}
@@ -690,12 +696,16 @@ public:
auto jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "srcActMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcActMalformed);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'tx_json.Account'.");
Account const jimmy{"jimmy"};
jv[jss::tx_json][jss::Account] = jimmy.human();
jrr = env.rpc("json", "sign_for", to_string(jv))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "srcActNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcActNotFound);
BEAST_EXPECT(jrr[jss::error_message] == "Source account not found.");
}
{
@@ -706,6 +716,7 @@ public:
auto jrr = env.rpc("json", "submit_multisigned", to_string(jv))[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "tx_json.Signers array may not be empty.");
env.close();
BEAST_EXPECT(env.seq(alice) == aliceSeq);
@@ -1068,6 +1079,9 @@ public:
STTx local = *tx.stx;
local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Empty SigningPubKey.");
@@ -1082,6 +1096,9 @@ public:
local.setFieldVL(sfTxnSignature, badSig);
// Signature should fail.
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Invalid signature.");
@@ -1095,6 +1112,9 @@ public:
local.setFieldU32(sfSequence, seq + 1);
// Signature should fail.
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Invalid signature.");
@@ -1105,6 +1125,9 @@ public:
STTx local = *tx.stx;
local[sfSigningPubKey] = alice.pk(); // Insert sfSigningPubKey
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Cannot both single- and multi-sign.");
@@ -1116,6 +1139,9 @@ public:
local.sign(alice.pk(), alice.sk());
local.setFieldVL(sfSigningPubKey, Blob()); // Empty SigningPubKey
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Cannot both single- and multi-sign.");
@@ -1131,6 +1157,9 @@ public:
signer.setFieldVL(sfTxnSignature, badSig);
// Signature should fail.
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception].asString().contains(
"Invalid signature on account r"));
@@ -1141,6 +1170,9 @@ public:
STTx local = *tx.stx;
local.peekFieldArray(sfSigners).clear(); // Empty Signers array.
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Invalid Signers array size.");
@@ -1186,6 +1218,9 @@ public:
bogie_));
STTx const local = *tx.stx;
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Invalid Signers array size.");
@@ -1195,6 +1230,9 @@ public:
JTx const tx = env.jt(noop(alice), Fee(2 * baseFee), Msig(alice));
STTx const local = *tx.stx;
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Invalid multisigner.");
@@ -1204,6 +1242,9 @@ public:
JTx const tx = env.jt(noop(alice), Fee(2 * baseFee), Msig(bogie_, bogie_));
STTx const local = *tx.stx;
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Duplicate Signers not allowed.");
@@ -1217,6 +1258,9 @@ public:
std::ranges::reverse(signers);
// Signature should fail.
auto const info = submitSTTx(local);
BEAST_EXPECT(info[jss::result][jss::error] == "invalidTransaction");
BEAST_EXPECT(!info[jss::result].isMember(jss::error_code));
BEAST_EXPECT(info[jss::result][jss::error_message].isNull());
BEAST_EXPECT(
info[jss::result][jss::error_exception] ==
"fails local checks: Unsorted Signers array.");
+2 -14
View File
@@ -777,13 +777,7 @@ class NFTokenBurn_test : public beast::unit_test::Suite
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
// Verify that the last page is present and contains one NFT.
auto const lastNFTokenPage = ac.view().peek(keylet::nftokenPageMax(alice));
@@ -815,13 +809,7 @@ class NFTokenBurn_test : public beast::unit_test::Suite
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
// Verify that the middle page is present.
auto const lastNFTokenPage = ac.view().peek(keylet::nftokenPageMax(alice));
+21 -12
View File
@@ -30,6 +30,7 @@
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/OpenView.h>
#include <xrpl/protocol/ApiVersion.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Protocol.h>
@@ -4653,18 +4654,22 @@ class NFTokenBaseUtil_test : public beast::unit_test::Suite
if (expect(
nftOffers.isMember(jss::result), "expected \"result\"", __FILE__, line))
{
if (expect(
nftOffers[jss::result].isMember(jss::error),
"expected \"error\"",
__FILE__,
line))
{
expect(
nftOffers[jss::result][jss::error].asString() == "objectNotFound",
"expected \"objectNotFound\"",
__FILE__,
line);
}
json::Value const& result = nftOffers[jss::result];
expect(
result[jss::error].asString() == "objectNotFound",
"expected \"objectNotFound\"",
__FILE__,
line);
expect(
result[jss::error_code] == RpcObjectNotFound,
"expected RpcObjectNotFound",
__FILE__,
line);
expect(
result[jss::error_message] == "The requested object was not found.",
"expected \"The requested object was not found.\"",
__FILE__,
line);
}
break;
}
@@ -4860,11 +4865,15 @@ class NFTokenBaseUtil_test : public beast::unit_test::Suite
// Sell-side marker passed to nft_buy_offers.
json::Value const result = queryWithMarker("nft_buy_offers", sellOfferIndex);
BEAST_EXPECT(result[jss::error].asString() == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid parameters.");
}
{
// Buy-side marker passed to nft_sell_offers.
json::Value const result = queryWithMarker("nft_sell_offers", buyOfferIndex);
BEAST_EXPECT(result[jss::error].asString() == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid parameters.");
}
// A same-side marker is still accepted. With a single offer on each
+7
View File
@@ -34,6 +34,7 @@
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Book.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -2755,6 +2756,8 @@ public:
jro = ledgerEntryOffer(env, bob, bobOfferSeq);
BEAST_EXPECT(jro[jss::error] == "entryNotFound");
BEAST_EXPECT(jro[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jro[jss::error_message] == "Entry not found.");
env.require(Owners(alice, 1), Owners(bob, 1));
}
@@ -2788,6 +2791,8 @@ public:
auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
BEAST_EXPECT(jro[jss::error] == "entryNotFound");
BEAST_EXPECT(jro[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jro[jss::error_message] == "Entry not found.");
};
testHelper3TokensMix(test);
}
@@ -2847,6 +2852,8 @@ public:
// Verify the offer was consumed
jro = ledgerEntryOffer(env, bob, bobOfferSeq);
BEAST_EXPECT(jro[jss::error] == "entryNotFound");
BEAST_EXPECT(jro[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jro[jss::error_message] == "Entry not found.");
// verify balances look right after the partial payment
// only 300 XRP should have been payed since that's all
+7
View File
@@ -30,6 +30,7 @@
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -1707,6 +1708,8 @@ public:
jro = ledgerEntryOffer(env, bob, bobOfferSeq);
BEAST_EXPECT(jro[jss::error] == "entryNotFound");
BEAST_EXPECT(jro[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jro[jss::error_message] == "Entry not found.");
env.require(Owners(alice, 1), Owners(bob, 1));
}
@@ -1738,6 +1741,8 @@ public:
auto jro = ledgerEntryOffer(env, bob, bobOfferSeq);
BEAST_EXPECT(jro[jss::error] == "entryNotFound");
BEAST_EXPECT(jro[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jro[jss::error_message] == "Entry not found.");
}
void
@@ -1798,6 +1803,8 @@ public:
// Verify the offer was consumed
jro = ledgerEntryOffer(env, bob, bobOfferSeq);
BEAST_EXPECT(jro[jss::error] == "entryNotFound");
BEAST_EXPECT(jro[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jro[jss::error_message] == "Entry not found.");
// verify balances look right after the partial payment
// only 300 XRP should be have been payed since that's all
+7 -2
View File
@@ -26,6 +26,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ApiVersion.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/PathAsset.h>
#include <xrpl/protocol/SField.h>
@@ -162,7 +163,9 @@ public:
g.signal();
});
BEAST_EXPECT(g.waitFor(5s));
BEAST_EXPECT(result.isMember(jss::error));
BEAST_EXPECT(result[jss::error] == "srcCurMalformed");
BEAST_EXPECT(result[jss::error_code] == RpcSrcCurMalformed);
BEAST_EXPECT(result[jss::error_message] == "Source currency is malformed.");
// Test rpc::tuning::max_auto_src_cur source currencies.
numSrc.clear();
@@ -189,7 +192,9 @@ public:
g.signal();
});
BEAST_EXPECT(g.waitFor(5s));
BEAST_EXPECT(result.isMember(jss::error));
BEAST_EXPECT(result[jss::error] == "internal");
BEAST_EXPECT(result[jss::error_code] == RpcInternal);
BEAST_EXPECT(result[jss::error_message] == "Internal error.");
}
void
+11 -6
View File
@@ -33,6 +33,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ApiVersion.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/SField.h>
@@ -318,7 +319,9 @@ public:
g.signal();
});
BEAST_EXPECT(g.waitFor(5s));
BEAST_EXPECT(result.isMember(jss::error));
BEAST_EXPECT(result[jss::error] == "srcCurMalformed");
BEAST_EXPECT(result[jss::error_code] == RpcSrcCurMalformed);
BEAST_EXPECT(result[jss::error_message] == "Source currency is malformed.");
// Test rpc::tuning::max_auto_src_cur source currencies.
for (auto i = 0; i < (rpc::tuning::kMaxAutoSrcCur - 1); ++i)
@@ -341,7 +344,9 @@ public:
g.signal();
});
BEAST_EXPECT(g.waitFor(5s));
BEAST_EXPECT(result.isMember(jss::error));
BEAST_EXPECT(result[jss::error] == "internal");
BEAST_EXPECT(result[jss::error_code] == RpcInternal);
BEAST_EXPECT(result[jss::error_message] == "Internal error.");
}
void
@@ -1964,9 +1969,9 @@ public:
auto const createPathElements = [](auto const& account1, auto const& account2) {
auto base = STPath{};
base.pushBack(
STPathElement{STPathElementType::Account, account1, xrpCurrency(), account1});
STPathElement{STPathElement::TypeAccount, account1, xrpCurrency(), account1});
auto const tail =
STPathElement{STPathElementType::Account, account2, xrpCurrency(), account2};
STPathElement{STPathElement::TypeAccount, account2, xrpCurrency(), account2};
return std::make_pair(base, tail);
};
@@ -2050,7 +2055,7 @@ public:
auto const makePath = [](AccountID const& account) {
auto p = STPath{};
p.pushBack(STPathElement{STPathElementType::Account, account, xrpCurrency(), account});
p.pushBack(STPathElement{STPathElement::TypeAccount, account, xrpCurrency(), account});
return p;
};
@@ -2174,7 +2179,7 @@ public:
},
// An explicit type mask vs. one derived from the populated fields.
{
STPathElement{STPathElementType::Account, kAccount, xrpCurrency(), kIssuer},
STPathElement{STPathElement::TypeAccount, kAccount, xrpCurrency(), kIssuer},
STPathElement{kAccount, PathAsset{xrpCurrency()}, kIssuer, false},
},
};
+70 -1
View File
@@ -1058,6 +1058,7 @@ struct PayChan_test : public beast::unit_test::Suite
auto const jrr = env.rpc("json", "account_channels", to_string(params))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "actMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jrr[jss::error_message] == "Account malformed.");
BEAST_EXPECT(!jrr.isMember(jss::ledger_index));
BEAST_EXPECT(!jrr.isMember(jss::ledger_current_index));
}
@@ -1232,7 +1233,9 @@ struct PayChan_test : public beast::unit_test::Suite
{
// degenerate case
auto const r = testLimit(env, alice, 0);
BEAST_EXPECT(r.isMember(jss::error_message));
BEAST_EXPECT(r[jss::error] == "invalidParams");
BEAST_EXPECT(r[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(r[jss::error_message] == "Invalid field 'limit'.");
}
{
@@ -1326,7 +1329,12 @@ struct PayChan_test : public beast::unit_test::Suite
auto const rs =
env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
auto const error = apiVersion < 2u ? "invalidParams" : "badKeyType";
auto const errorCode = apiVersion < 2u ? RpcInvalidParams : RpcBadKeyType;
auto const errorMessage =
apiVersion < 2u ? "Invalid field 'key_type'." : "Bad key type.";
BEAST_EXPECT(rs[jss::error] == error);
BEAST_EXPECT(rs[jss::error_code] == errorCode);
BEAST_EXPECT(rs[jss::error_message] == errorMessage);
});
}
@@ -1415,22 +1423,40 @@ struct PayChan_test : public beast::unit_test::Suite
auto const pkAsHex = sliceToHex(pk.slice());
auto rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000x", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 ", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "x1000", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "x", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, " ", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 1000", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1,000", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, " 1000", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "", sig);
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel amount is malformed.");
}
{
// malformed channel
@@ -1439,22 +1465,34 @@ struct PayChan_test : public beast::unit_test::Suite
chan1StrBad.pop_back();
auto rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig);
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel is malformed.");
rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel is malformed.");
chan1StrBad = chan1Str;
chan1StrBad.push_back('0');
rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig);
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel is malformed.");
rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel is malformed.");
chan1StrBad = chan1Str;
chan1StrBad.back() = 'x';
rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig);
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel is malformed.");
rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
BEAST_EXPECT(rv[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rv[jss::error_message] == "Payment channel is malformed.");
}
{
// channel_id is not a string.
@@ -1467,6 +1505,8 @@ struct PayChan_test : public beast::unit_test::Suite
auto const ra =
env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(ra[jss::error] == "invalidParams");
BEAST_EXPECT(ra[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ra[jss::error_message] == "Invalid parameters.");
}
{
// channel_id is not a string.
@@ -1479,6 +1519,8 @@ struct PayChan_test : public beast::unit_test::Suite
auto const rv =
env.rpc("json", "channel_verify", args.toStyledString())[jss::result];
BEAST_EXPECT(rv[jss::error] == "invalidParams");
BEAST_EXPECT(rv[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(rv[jss::error_message] == "Invalid parameters.");
}
{
// give an ill formed base 58 public key
@@ -1537,6 +1579,8 @@ struct PayChan_test : public beast::unit_test::Suite
// Try to authorize using an unknown key type, except an error:
auto const rs1 = env.rpc("channel_authorize", "charlie", "nyx", chan, "1000");
BEAST_EXPECT(rs1[jss::error] == "badKeyType");
BEAST_EXPECT(rs1[jss::error_code] == RpcBadKeyType);
BEAST_EXPECT(rs1[jss::error_message] == "Bad key type.");
// Try to authorize using secp256k1; the authorization _should_
// succeed but the verification should fail:
@@ -1562,10 +1606,16 @@ struct PayChan_test : public beast::unit_test::Suite
// send malformed amounts rpc requests
auto rs = env.rpc("channel_authorize", "alice", chan1Str, "1000x");
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rs[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rs[jss::error_message] == "Payment channel amount is malformed.");
rs = env.rpc("channel_authorize", "alice", chan1Str, "x1000");
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rs[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rs[jss::error_message] == "Payment channel amount is malformed.");
rs = env.rpc("channel_authorize", "alice", chan1Str, "x");
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rs[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rs[jss::error_message] == "Payment channel amount is malformed.");
{
// Missing channel_id
json::Value args{json::ValueType::Object};
@@ -1574,6 +1624,8 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::passphrase] = "passphrase_can_be_anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "invalidParams");
BEAST_EXPECT(rs[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(rs[jss::error_message] == "Missing field 'channel_id'.");
}
{
// Missing amount
@@ -1583,6 +1635,8 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::passphrase] = "passphrase_can_be_anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "invalidParams");
BEAST_EXPECT(rs[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(rs[jss::error_message] == "Missing field 'amount'.");
}
{
// Missing key_type and no secret.
@@ -1592,6 +1646,8 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::passphrase] = "passphrase_can_be_anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "invalidParams");
BEAST_EXPECT(rs[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(rs[jss::error_message] == "Missing field 'secret'.");
}
{
// Both passphrase and seed specified.
@@ -1603,6 +1659,11 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::seed] = "seed can be anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "invalidParams");
BEAST_EXPECT(rs[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
rs[jss::error_message] ==
"Exactly one of the following must be specified: passphrase, secret, seed or "
"seed_hex");
}
{
// channel_id is not exact hex.
@@ -1613,6 +1674,8 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::passphrase] = "passphrase_can_be_anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "channelMalformed");
BEAST_EXPECT(rs[jss::error_code] == RpcChannelMalformed);
BEAST_EXPECT(rs[jss::error_message] == "Payment channel is malformed.");
}
{
// amount is not a string
@@ -1623,6 +1686,8 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::passphrase] = "passphrase_can_be_anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rs[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rs[jss::error_message] == "Payment channel amount is malformed.");
}
{
// Amount is not a decimal string.
@@ -1633,6 +1698,8 @@ struct PayChan_test : public beast::unit_test::Suite
args[jss::passphrase] = "passphrase_can_be_anything";
rs = env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
BEAST_EXPECT(rs[jss::error_code] == RpcChannelAmtMalformed);
BEAST_EXPECT(rs[jss::error_message] == "Payment channel amount is malformed.");
}
}
}
@@ -1883,6 +1950,8 @@ struct PayChan_test : public beast::unit_test::Suite
)*";
auto const r = env.rpc("json", "channel_verify", txn);
BEAST_EXPECT(r["result"]["error"] == "publicMalformed");
BEAST_EXPECT(r["result"]["error_code"] == RpcPublicMalformed);
BEAST_EXPECT(r["result"]["error_message"] == "Public key is malformed.");
}
}
+2 -2
View File
@@ -256,7 +256,7 @@ struct PayStrandMPT_test : public beast::unit_test::Suite
usd,
STPath({
STPathElement{
STPathElementType::Currency, xrpAccount(), xrpCurrency(), xrpAccount()},
STPathElement::TypeCurrency, xrpAccount(), xrpCurrency(), xrpAccount()},
}),
tesSUCCESS,
makeEndpointStep(alice, gw, usd),
@@ -583,7 +583,7 @@ struct PayStrandMPT_test : public beast::unit_test::Suite
inputs.defaultPathsAllowed = true;
try
{
PaymentSandbox sb{env.current().get(), ApplyFlags::None};
PaymentSandbox sb{env.current().get(), TapNone};
{
auto const r = ::xrpl::path::RippleCalc::rippleCalculate(
sb,
+4 -5
View File
@@ -225,7 +225,7 @@ public:
else
{
col.emplace_back(
STPathElementType::Boundary,
STPathElement::Type::TypeBoundary,
acc.value_or(AccountID{}),
cur.value_or(Currency{}),
iss.value_or(AccountID{}));
@@ -684,7 +684,7 @@ struct PayStrand_test : public beast::unit_test::Suite
usd,
STPath({
STPathElement{
STPathElementType::Currency, xrpAccount(), xrpCurrency(), xrpAccount()},
STPathElement::TypeCurrency, xrpAccount(), xrpCurrency(), xrpAccount()},
}),
tesSUCCESS,
D{.src = alice, .dst = gw, .currency = usdC},
@@ -770,8 +770,7 @@ struct PayStrand_test : public beast::unit_test::Suite
env,
usd,
std::nullopt,
STPath({STPathElement(
STPathElementType::None, xrpAccount(), xrpCurrency(), xrpAccount())}),
STPath({STPathElement(0, xrpAccount(), xrpCurrency(), xrpAccount())}),
temBAD_PATH);
// The same account can't appear more than once on a path
@@ -1079,7 +1078,7 @@ struct PayStrand_test : public beast::unit_test::Suite
inputs.defaultPathsAllowed = true;
try
{
PaymentSandbox sb{env.current().get(), ApplyFlags::None};
PaymentSandbox sb{env.current().get(), TapNone};
{
auto const r = ::xrpl::path::RippleCalc::rippleCalculate(
sb,
+1 -1
View File
@@ -88,7 +88,7 @@ struct PseudoTx_test : public beast::unit_test::Suite
BEAST_EXPECT(!passesLocalChecks(stx, reason));
BEAST_EXPECT(reason == "Cannot submit pseudo transactions.");
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, stx, TapNone, j);
BEAST_EXPECT(!result.applied && result.ter == temINVALID);
return result.applied;
});
+4 -2
View File
@@ -13,6 +13,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Quality.h>
#include <xrpl/protocol/SField.h>
@@ -42,8 +43,9 @@ class ReducedOffer_test : public beast::unit_test::Suite
{
json::Value ledgerOffer = ledgerEntryOffer(env, acct, offerSeq);
return !(
ledgerOffer.isMember(jss::error) &&
ledgerOffer[jss::error].asString() == "entryNotFound");
ledgerOffer[jss::error].asString() == "entryNotFound" &&
ledgerOffer[jss::error_code] == RpcEntryNotFound &&
ledgerOffer[jss::error_message] == "Entry not found.");
}
// Common code to clean up unneeded offers.
+2 -4
View File
@@ -103,8 +103,7 @@ struct Regression_test : public beast::unit_test::Suite
auto const jt = env.jt(pay(env.master, "alice", aliceAmount));
OpenView accum(&*next);
auto const result =
xrpl::apply(env.app(), accum, *jt.stx, ApplyFlags::None, env.journal);
auto const result = xrpl::apply(env.app(), accum, *jt.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(result.ter));
BEAST_EXPECT(result.applied);
@@ -127,8 +126,7 @@ struct Regression_test : public beast::unit_test::Suite
OpenView accum(&*next);
auto const result =
xrpl::apply(env.app(), accum, *jt.stx, ApplyFlags::None, env.journal);
auto const result = xrpl::apply(env.app(), accum, *jt.stx, TapNone, env.journal);
BEAST_EXPECT(result.ter == tecINSUFF_FEE);
BEAST_EXPECT(result.applied);
+13 -9
View File
@@ -83,8 +83,8 @@ class SHAMapStore_test : public beast::unit_test::Suite
// after the health check that gates it, and kFinished once a rotation has
// run to completion. kExpired is logged by healthWait() when the circuit
// breaker trips.
static constexpr char const* kRotating = "rotating";
static constexpr char const* kFinished = "finished rotation";
static constexpr char const* kRotating = "ROTATING:";
static constexpr char const* kFinished = "FINISHED ROTATION:";
static constexpr char const* kExpired = "unable to make progress";
// A Logs implementation that records every message the store's own
@@ -302,10 +302,14 @@ class SHAMapStore_test : public beast::unit_test::Suite
}
static bool
bad(json::Value const& json, ErrorCodeI error = RpcLgrNotFound)
bad(json::Value const& json,
std::string const& token,
ErrorCodeI error,
std::string const& message)
{
return json.isMember(jss::result) && rpc::containsError(json[jss::result]) &&
json[jss::result][jss::error_code] == error;
return json.isMember(jss::result) && json[jss::result][jss::error] == token &&
json[jss::result][jss::error_code] == error &&
json[jss::result][jss::error_message] == message;
}
std::string
@@ -883,7 +887,7 @@ public:
std::map<std::uint32_t, json::Value const> ledgers;
auto ledgerTmp = env.rpc("ledger", "0");
BEAST_EXPECT(bad(ledgerTmp));
BEAST_EXPECT(bad(ledgerTmp, "lgrNotFound", RpcLgrNotFound, "ledgerNotFound"));
ledgers.emplace(1, env.rpc("ledger", "1"));
BEAST_EXPECT(goodLedger(env, ledgers[1], "1"));
@@ -895,10 +899,10 @@ public:
BEAST_EXPECT(goodLedger(env, ledgerTmp, "3"));
ledgerTmp = env.rpc("ledger", "4");
BEAST_EXPECT(bad(ledgerTmp));
BEAST_EXPECT(bad(ledgerTmp, "lgrNotFound", RpcLgrNotFound, "ledgerNotFound"));
ledgerTmp = env.rpc("ledger", "100");
BEAST_EXPECT(bad(ledgerTmp));
BEAST_EXPECT(bad(ledgerTmp, "lgrNotFound", RpcLgrNotFound, "ledgerNotFound"));
auto const firstSeq = waitForReady(env);
auto lastRotated = firstSeq - 1;
@@ -987,7 +991,7 @@ public:
// Because advisory_delete is unset,
// "can_delete" is disabled.
auto const canDelete = env.rpc("can_delete");
BEAST_EXPECT(bad(canDelete, RpcNotEnabled));
BEAST_EXPECT(bad(canDelete, "notEnabled", RpcNotEnabled, "Not enabled in configuration."));
// Close ledgers without triggering a rotate
for (; ledgerSeq < lastRotated + kDeleteInterval; ++ledgerSeq)
+8 -10
View File
@@ -990,8 +990,8 @@ public:
sponsor::SponseeAcc(alice),
Seq(1),
Fee(baseFee));
auto const pf = preflight(
env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -1006,8 +1006,8 @@ public:
sponsor::SponseeAcc(alice),
Seq(1),
Fee(baseFee));
auto const pf = preflight(
env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -1021,8 +1021,8 @@ public:
sponsor::SponseeAcc(alice),
Seq(1),
Fee(baseFee));
auto const pf = preflight(
env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -2318,8 +2318,7 @@ public:
Seq(env.seq(alice)),
sponsor::As(carol, spfSponsorFee));
auto const result =
xrpl::apply(env.app(), overlay, *jt.stx, ApplyFlags::None, env.journal);
auto const result = xrpl::apply(env.app(), overlay, *jt.stx, TapNone, env.journal);
BEAST_EXPECT(result.ter == tecINSUFF_FEE);
BEAST_EXPECT(result.applied);
@@ -2372,8 +2371,7 @@ public:
Fee(fixFee),
sponsor::As(sponsor, spfSponsorFee));
auto const pf =
preflight(env.app(), overlay.rules(), *jt.stx, ApplyFlags::None, env.journal);
auto const pf = preflight(env.app(), overlay.rules(), *jt.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
auto const pc = preclaim(pf, env.app(), overlay);
BEAST_EXPECT(isTesSuccess(pc.ter));
+1 -1
View File
@@ -252,7 +252,7 @@ class TheoreticalQuality_test : public beast::unit_test::Suite
std::shared_ptr<ReadView const> closed,
std::optional<Quality> const& expectedQ = {})
{
PaymentSandbox const sb(closed.get(), ApplyFlags::None);
PaymentSandbox const sb(closed.get(), TapNone);
AMMContext ammContext(rcp.srcAccount, false);
auto const sendMaxIssue = [&rcp] -> std::optional<Asset> {
@@ -20,6 +20,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Protocol.h>
@@ -1032,15 +1033,25 @@ struct TransactionProposalCancel_test : public beast::unit_test::Suite
{
json::Value noTicket;
noTicket[jss::account] = target.human();
BEAST_EXPECT(ledgerEntry(noTicket)[jss::error] == "malformedRequest");
auto const noTicketResult = ledgerEntry(noTicket);
BEAST_EXPECT(noTicketResult[jss::error] == "malformedRequest");
BEAST_EXPECT(noTicketResult[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(noTicketResult[jss::error_message] == "Missing field 'ticket_seq'.");
json::Value noAccount;
noAccount[jss::ticket_seq] = ticketSeq;
BEAST_EXPECT(ledgerEntry(noAccount)[jss::error] == "malformedRequest");
auto const noAccountResult = ledgerEntry(noAccount);
BEAST_EXPECT(noAccountResult[jss::error] == "malformedRequest");
BEAST_EXPECT(noAccountResult[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(noAccountResult[jss::error_message] == "Missing field 'account'.");
json::Value badAccount = byPair;
badAccount[jss::account] = "not an account";
BEAST_EXPECT(ledgerEntry(badAccount)[jss::error] == "malformedAddress");
auto const badAccountResult = ledgerEntry(badAccount);
BEAST_EXPECT(badAccountResult[jss::error] == "malformedAddress");
BEAST_EXPECT(badAccountResult[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
badAccountResult[jss::error_message] == "Invalid field 'account', not AccountID.");
}
// Listed for the proposer, who owns it, and not for the target.
@@ -1057,6 +1068,8 @@ struct TransactionProposalCancel_test : public beast::unit_test::Suite
{
auto const jrr = ledgerEntry(byPair);
BEAST_EXPECT(jrr[jss::error] == "entryNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jrr[jss::error_message] == "Entry not found.");
BEAST_EXPECT(!jrr.isMember(jss::node));
BEAST_EXPECT(jrr[jss::index] == to_string(proposalID));
}
@@ -1603,7 +1603,7 @@ struct TransactionProposalReservedTicket_test : public beast::unit_test::Suite
auto const stx = rebuilt(mutated);
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, *stx, TapNone, j);
BEAST_EXPECT(result.ter == temBAD_SIGNATURE);
BEAST_EXPECT(!result.applied);
return result.applied;
@@ -1639,7 +1639,7 @@ struct TransactionProposalReservedTicket_test : public beast::unit_test::Suite
auto const stx = rebuilt(mutated);
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *stx, ApplyFlags::None, j);
auto const result = xrpl::apply(env.app(), view, *stx, TapNone, j);
BEAST_EXPECT(result.ter == temINVALID);
BEAST_EXPECT(!result.applied);
return result.applied;
+5
View File
@@ -14,6 +14,7 @@
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/TER.h>
@@ -66,6 +67,8 @@ class TrustAndBalance_test : public beast::unit_test::Suite
// reflects this
auto jrr = ledgerEntryState(env, gw, alice, "USD");
BEAST_EXPECT(jrr[jss::error] == "entryNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jrr[jss::error_message] == "Entry not found.");
// now create a credit limit
env(trust(alice, gw["USD"](800)));
@@ -100,6 +103,8 @@ class TrustAndBalance_test : public beast::unit_test::Suite
// ensure line is deleted
jrr = ledgerEntryState(env, gw, alice, "USD");
BEAST_EXPECT(jrr[jss::error] == "entryNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcEntryNotFound);
BEAST_EXPECT(jrr[jss::error_message] == "Entry not found.");
// TODO Check in both owner books.
+12 -11
View File
@@ -989,8 +989,7 @@ public:
Env::ParsedResult parsed;
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result =
xrpl::apply(env.app(), view, *jt.stx, ApplyFlags::None, env.journal);
auto const result = xrpl::apply(env.app(), view, *jt.stx, TapNone, env.journal);
parsed.ter = result.ter;
return result.applied;
});
@@ -2429,8 +2428,8 @@ public:
env.memoize("carol");
{
auto const jtx = env.jt(offerCancel(alice, 3), Seq(5), Fee(10));
auto const pf = preflight(
env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(10));
@@ -2441,8 +2440,8 @@ public:
auto const usd = alice["USD"];
auto const jtx = env.jt(trust("carol", usd(50000000)), Seq(1), Fee(10));
auto const pf = preflight(
env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(10));
@@ -2451,8 +2450,8 @@ public:
{
auto const jtx = env.jt(ticket::create(alice, 1), Seq(1), Fee(10));
auto const pf = preflight(
env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
auto const pf =
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(10));
@@ -3232,7 +3231,9 @@ public:
{
auto const info = env.rpc("json", "account_info", to_string(prevLedgerWithQueue));
BEAST_EXPECT(info.isMember(jss::result) && rpc::containsError(info[jss::result]));
BEAST_EXPECT(info[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(info[jss::result][jss::error_message] == "Invalid parameters.");
}
env.close();
@@ -4011,7 +4012,7 @@ public:
// be callable via RPC.)
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const tx = env.jt(noop(alice), Seq(aliceSeq), Fee(openLedgerCost(env)));
auto const result = xrpl::apply(env.app(), view, *tx.stx, ApplyFlags::Unlimited, j);
auto const result = xrpl::apply(env.app(), view, *tx.stx, TapUnlimited, j);
BEAST_EXPECT(isTesSuccess(result.ter) && result.applied);
return result.applied;
});
@@ -4079,7 +4080,7 @@ public:
// be callable via RPC.)
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const tx = env.jt(noop(alice), ticket::Use(tktSeq0 + 1), Fee(openLedgerCost(env)));
auto const result = xrpl::apply(env.app(), view, *tx.stx, ApplyFlags::Unlimited, j);
auto const result = xrpl::apply(env.app(), view, *tx.stx, TapUnlimited, j);
BEAST_EXPECT(isTesSuccess(result.ter) && result.applied);
return result.applied;
});
+1 -2
View File
@@ -122,8 +122,7 @@ InvariantsBase::doInvariantCheck(
OpenView ov{*env.current()};
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
// Invariants normally run in the Transaction's "apply" (operator()) context, and can always
// access global Rules.
@@ -845,13 +845,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -906,13 +900,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -1035,13 +1023,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -1525,7 +1507,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sle = ac.view().peek(vaultKeylet);
@@ -1592,7 +1574,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
// visitEntry only runs for entries the transaction touched, so
@@ -1649,8 +1631,7 @@ class InvariantsMisc_test : public InvariantsBase
STTx const tx{ttACCOUNT_SET, [](STObject&) {}};
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
FailingTxInvariantCheck failing;
@@ -681,7 +681,7 @@ class InvariantsPseudoAccount_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleBroker = ac.view().peek(brokerKeylet);
@@ -733,7 +733,7 @@ class InvariantsPseudoAccount_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleBroker = ac.view().peek(brokerKeylet);
@@ -781,7 +781,7 @@ class InvariantsPseudoAccount_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleBroker = ac.view().peek(brokerKeylet);
@@ -1131,13 +1131,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -1189,7 +1183,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -1366,13 +1360,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -1427,13 +1415,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto const sleLoan = ac.view().peek(loanKeylet);
@@ -1537,7 +1519,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules());
{
+4 -3
View File
@@ -1154,6 +1154,8 @@ class LoanBroker_test : public beast::unit_test::Suite
auto const jrr = env.rpc("submit", strHex(s.slice()))[jss::result];
// fails in doSubmit() on STTx construction
BEAST_EXPECT(jrr[jss::error] == "invalidTransaction");
BEAST_EXPECT(!jrr.isMember(jss::error_code));
BEAST_EXPECT(jrr[jss::error_message].isNull());
BEAST_EXPECT(jrr[jss::error_exception] == "invalid native account");
}
@@ -1271,8 +1273,7 @@ class LoanBroker_test : public beast::unit_test::Suite
OpenView ov{*env.current()};
test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink};
ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog};
if (auto const sleBroker = ac.view().peek(keylet::loanBroker(brokerKeylet.key)))
{
@@ -1285,7 +1286,7 @@ class LoanBroker_test : public beast::unit_test::Suite
// Invoke preclaim against the mutated (ApplyView) view; triggers
// nullptr deref
PreclaimContext const pctx{env.app(), ac.view(), tesSUCCESS, tx, ApplyFlags::None, jlog};
PreclaimContext const pctx{env.app(), ac.view(), tesSUCCESS, tx, TapNone, jlog};
(void)LoanBrokerCoverDeposit::preclaim(pctx);
}
@@ -190,6 +190,8 @@ private:
BEAST_EXPECT(jr.isMember(jss::result));
auto const jResult = jr[jss::result];
BEAST_EXPECT(jResult[jss::error] == "invalidTransaction");
BEAST_EXPECT(!jResult.isMember(jss::error_code));
BEAST_EXPECT(jResult[jss::error_message].isNull());
BEAST_EXPECT(
jResult[jss::error_exception] ==
"fails local checks: Transaction has bad signature.");
+4 -6
View File
@@ -18,6 +18,7 @@
#include <xrpl/beast/xor_shift_engine.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/KeyType.h>
@@ -126,12 +127,9 @@ private:
return params;
}();
auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams));
BEAST_EXPECT(
jSignBorrower.isMember(jss::result) &&
jSignBorrower[jss::result].isMember(jss::error) &&
jSignBorrower[jss::result][jss::error] == "invalidParams" &&
jSignBorrower[jss::result].isMember(jss::error_message) &&
jSignBorrower[jss::result][jss::error_message] == target);
BEAST_EXPECT(jSignBorrower[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jSignBorrower[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jSignBorrower[jss::result][jss::error_message] == target);
}
}
{
+2 -1
View File
@@ -196,7 +196,8 @@ private:
jvResult[jss::tx_blob] = strHex(local.getSerializer().slice());
auto res = env.rpc("json", "submit", to_string(jvResult))["result"];
BEAST_EXPECT(
res[jss::error] == "invalidTransaction" &&
res[jss::error] == "invalidTransaction" && !res.isMember(jss::error_code) &&
res[jss::error_message].isNull() &&
res[jss::error_exception] ==
"fails local checks: Counterparty: Invalid signature.");
});
+35 -11
View File
@@ -172,7 +172,7 @@ private:
jvParams[jss::ledger_index] = jss::validated;
jvParams[jss::vault] = to_string(UInt256(42));
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "entryNotFound");
checkError(jvVault[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
@@ -182,7 +182,7 @@ private:
jvParams[jss::vault][jss::owner] = issuer.human();
jvParams[jss::vault][jss::seq] = 1'000'000;
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "entryNotFound");
checkError(jvVault[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
@@ -191,7 +191,11 @@ private:
jvParams[jss::ledger_index] = jss::validated;
jvParams[jss::vault] = 42;
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
checkError(
jvVault[jss::result],
"malformedRequest",
RpcInvalidParams,
"Invalid field 'vault', not hex string or object.");
}
{
@@ -201,7 +205,11 @@ private:
jvParams[jss::vault][jss::owner] = 42;
jvParams[jss::vault][jss::seq] = sequence;
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedOwner");
checkError(
jvVault[jss::result],
"malformedOwner",
RpcInvalidParams,
"Invalid field 'owner', not AccountID.");
}
{
@@ -211,7 +219,11 @@ private:
jvParams[jss::vault][jss::owner] = issuer.human();
jvParams[jss::vault][jss::seq] = "foo";
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
checkError(
jvVault[jss::result],
"malformedRequest",
RpcInvalidParams,
"Invalid field 'seq', not number.");
}
{
@@ -221,7 +233,11 @@ private:
jvParams[jss::vault][jss::owner] = issuer.human();
jvParams[jss::vault][jss::seq] = -1;
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
checkError(
jvVault[jss::result],
"malformedRequest",
RpcInvalidParams,
"Invalid field 'seq', not number.");
}
{
@@ -231,7 +247,11 @@ private:
jvParams[jss::vault][jss::owner] = issuer.human();
jvParams[jss::vault][jss::seq] = 1e20;
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
checkError(
jvVault[jss::result],
"malformedRequest",
RpcInvalidParams,
"Invalid field 'seq', not number.");
}
{
@@ -241,7 +261,11 @@ private:
jvParams[jss::vault][jss::owner] = issuer.human();
jvParams[jss::vault][jss::seq] = true;
auto jvVault = env.rpc("json", "ledger_entry", to_string(jvParams));
BEAST_EXPECT(jvVault[jss::result][jss::error].asString() == "malformedRequest");
checkError(
jvVault[jss::result],
"malformedRequest",
RpcInvalidParams,
"Invalid field 'seq', not number.");
}
{
@@ -500,8 +524,8 @@ private:
{
testcase("RPC vault_info command line invalid index");
json::Value jv = env.rpc("vault_info", "foobar", "validated");
BEAST_EXPECT(jv[jss::error].asString() == "invalidParams");
json::Value const jv = env.rpc("vault_info", "foobar", "validated");
checkError(jv, "invalidParams", RpcInvalidParams, "Invalid parameters.");
}
{
@@ -519,7 +543,7 @@ private:
{
testcase("RPC vault_info command line invalid ledger");
json::Value jv = env.rpc("vault_info", strHex(keylet.key), "0");
BEAST_EXPECT(jv[jss::result][jss::error].asString() == "lgrNotFound");
checkError(jv[jss::result], "lgrNotFound", RpcLgrNotFound, "ledgerNotFound");
}
}
+1 -1
View File
@@ -114,7 +114,7 @@ private:
auto const peek = [keylet, &env, this](std::function<bool(SLE&, SLE&)> fn) -> bool {
return env.app().getOpenLedger().modify(
[&](OpenView& view, beast::Journal j) -> bool {
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
auto const vault = sb.peek(keylet::vault(keylet.key));
if (!BEAST_EXPECT(vault))
return false;
+1 -1
View File
@@ -304,7 +304,7 @@ private:
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
for (auto const field : encryptedBalanceFields)
{
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
auto const token = sb.peek(tokenKeylet);
if (!BEAST_EXPECT(token))
return false;
+1 -1
View File
@@ -1939,7 +1939,7 @@ negUnlSizeTest(
bool
applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass)
{
auto const res = apply(env.app(), view, tx, ApplyFlags::None, env.journal);
auto const res = apply(env.app(), view, tx, ApplyFlags::TapNone, env.journal);
if (pass)
{
return isTesSuccess(res.ter);
+2 -2
View File
@@ -125,7 +125,7 @@ inline TestPath&
TestPath::pushBack(Issue const& iss)
{
path.emplaceBack(
STPathElementType::Currency | STPathElementType::Issuer,
STPathElement::TypeCurrency | STPathElement::TypeIssuer,
beast::kZero,
iss.currency,
iss.account);
@@ -136,7 +136,7 @@ inline TestPath&
TestPath::pushBack(MPTIssue const& iss)
{
path.emplaceBack(
STPathElementType::Mpt | STPathElementType::Issuer,
STPathElement::TypeMpt | STPathElement::TypeIssuer,
beast::kZero,
iss.getMptID(),
iss.getIssuer());
+6 -6
View File
@@ -570,10 +570,10 @@ cpe(PathAsset const& pa)
{
return pa.visit(
[](Currency const& currency) {
return STPathElement(STPathElementType::Currency, xrpAccount(), currency, xrpAccount());
return STPathElement(STPathElement::TypeCurrency, xrpAccount(), currency, xrpAccount());
},
[](MPTID const& mpt) {
return STPathElement(STPathElementType::Mpt, xrpAccount(), mpt, xrpAccount());
return STPathElement(STPathElement::TypeMpt, xrpAccount(), mpt, xrpAccount());
});
};
@@ -590,14 +590,14 @@ ipe(Asset const& asset)
return asset.visit(
[](Issue const& issue) {
return STPathElement(
STPathElementType::Currency | STPathElementType::Issuer,
STPathElement::TypeCurrency | STPathElement::TypeIssuer,
xrpAccount(),
issue.currency,
issue.account);
},
[](MPTIssue const& issue) {
return STPathElement(
STPathElementType::Mpt | STPathElementType::Issuer,
STPathElement::TypeMpt | STPathElement::TypeIssuer,
xrpAccount(),
issue.getMptID(),
issue.getIssuer());
@@ -608,14 +608,14 @@ ipe(Asset const& asset)
STPathElement
iape(AccountID const& account)
{
return STPathElement(STPathElementType::Issuer, xrpAccount(), xrpCurrency(), account);
return STPathElement(STPathElement::TypeIssuer, xrpAccount(), xrpCurrency(), account);
};
// Account path element
STPathElement
ape(AccountID const& a)
{
return STPathElement(STPathElementType::Account, a, xrpCurrency(), xrpAccount());
return STPathElement(STPathElement::TypeAccount, a, xrpCurrency(), xrpAccount());
};
bool
+1 -1
View File
@@ -32,7 +32,7 @@ bumpLastPage(
{
std::expected<void, Error> res{};
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) -> bool {
Sandbox sb(&view, ApplyFlags::None);
Sandbox sb(&view, TapNone);
// Find the root page
auto const sleRoot = sb.peek(directory);
+3 -3
View File
@@ -313,7 +313,7 @@ struct Directory_test : public beast::unit_test::Suite
// All the offers have been cancelled, so the book
// should have no entries and be empty:
{
Sandbox const sb(env.closed().get(), ApplyFlags::None);
Sandbox const sb(env.closed().get(), TapNone);
UInt256 const bookBase = getBookBase({xrpIssue(), usd, std::nullopt});
BEAST_EXPECT(dirIsEmpty(sb, keylet::page(bookBase)));
@@ -352,7 +352,7 @@ struct Directory_test : public beast::unit_test::Suite
{
// Create a chain of three pages:
Sandbox sb(env.closed().get(), ApplyFlags::None);
Sandbox sb(env.closed().get(), TapNone);
makePages(sb, kBase, 3);
// Insert an item in the middle page:
@@ -376,7 +376,7 @@ struct Directory_test : public beast::unit_test::Suite
{
// Create a chain of four pages:
Sandbox sb(env.closed().get(), ApplyFlags::None);
Sandbox sb(env.closed().get(), TapNone);
makePages(sb, kBase, 4);
// Now add items on pages 1 and 2:
+11 -11
View File
@@ -131,7 +131,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
STAmount const toDebit(usdGw1(20));
{
// accountSend, no deferredCredits
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
auto const iss = usdGw1;
auto const startingAmount =
@@ -156,7 +156,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{
// directSendNoFee, no deferredCredits
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
auto const iss = usdGw1;
auto const startingAmount =
@@ -177,7 +177,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{
// accountSend, w/ deferredCredits
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox pv(&av);
auto const iss = usdGw1;
@@ -205,7 +205,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{
// directSendNoFee, w/ deferredCredits
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox pv(&av);
auto const iss = usdGw1;
@@ -221,7 +221,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{
// redeemIOU, w/ deferredCredits
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox pv(&av);
auto const iss = usdGw1;
@@ -237,7 +237,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{
// issueIOU, w/ deferredCredits
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox pv(&av);
auto const iss = usdGw1;
@@ -253,7 +253,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{
// accountSend, w/ deferredCredits and stacked views
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox pv(&av);
auto const iss = usdGw1;
@@ -319,7 +319,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
STAmount const hugeAmt(
issue, STAmount::kMaxValue, STAmount::kMaxOffset - 1, false, STAmount::Unchecked{});
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox pv(&av);
pv.creditHookIOU(gw, alice, hugeAmt, -tinyAmt);
BEAST_EXPECT(pv.balanceHookIOU(alice, gw, hugeAmt) == tinyAmt);
@@ -347,7 +347,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
env.fund(reserve(env, 1), alice);
env.close();
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox sb(&av);
{
// Send alice an amount and spend it. The deferredCredits will cause
@@ -380,7 +380,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
auto const usd = gw["USD"];
Account const alice("alice");
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox sb(&av);
// The currency we pass for the last argument mimics the currency that
@@ -412,7 +412,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
env.fund(XRP(10000), alice, sponsor);
env.close();
ApplyViewImpl av(&*env.current(), ApplyFlags::None);
ApplyViewImpl av(&*env.current(), TapNone);
PaymentSandbox sb(&av);
// Test basic owner count hook without sponsor
+9 -9
View File
@@ -189,7 +189,7 @@ class View_test : public beast::unit_test::Suite
Env env(*this);
wipe(env.app().getOpenLedger());
auto const open = env.current();
ApplyViewImpl v(&*open, ApplyFlags::None);
ApplyViewImpl v(&*open, TapNone);
succ(v, 0, std::nullopt);
v.insert(sle(1));
BEAST_EXPECT(v.exists(k(1)));
@@ -222,7 +222,7 @@ class View_test : public beast::unit_test::Suite
Env env(*this);
wipe(env.app().getOpenLedger());
auto const open = env.current();
ApplyViewImpl v0(&*open, ApplyFlags::None);
ApplyViewImpl v0(&*open, TapNone);
v0.insert(sle(1));
v0.insert(sle(2));
v0.insert(sle(4));
@@ -288,7 +288,7 @@ class View_test : public beast::unit_test::Suite
Env env(*this);
wipe(env.app().getOpenLedger());
auto const open = env.current();
ApplyViewImpl v0(&*open, ApplyFlags::None);
ApplyViewImpl v0(&*open, TapNone);
v0.rawInsert(sle(1, 1));
v0.rawInsert(sle(2, 2));
v0.rawInsert(sle(4, 4));
@@ -368,22 +368,22 @@ class View_test : public beast::unit_test::Suite
BEAST_EXPECT(v1.seq() == v0.seq());
BEAST_EXPECT(v1.parentCloseTime() == v1.parentCloseTime());
ApplyViewImpl v2(&v1, ApplyFlags::Retry);
ApplyViewImpl v2(&v1, TapRetry);
BEAST_EXPECT(v2.parentCloseTime() == v1.parentCloseTime());
BEAST_EXPECT(v2.seq() == v1.seq());
BEAST_EXPECT(v2.flags() == ApplyFlags::Retry);
BEAST_EXPECT(v2.flags() == TapRetry);
Sandbox const v3(&v2);
BEAST_EXPECT(v3.seq() == v2.seq());
BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime());
BEAST_EXPECT(v3.flags() == ApplyFlags::Retry);
BEAST_EXPECT(v3.flags() == TapRetry);
}
{
ApplyViewImpl v1(&v0, ApplyFlags::Retry);
ApplyViewImpl v1(&v0, TapRetry);
PaymentSandbox v2(&v1);
BEAST_EXPECT(v2.seq() == v0.seq());
BEAST_EXPECT(v2.parentCloseTime() == v0.parentCloseTime());
BEAST_EXPECT(v2.flags() == ApplyFlags::Retry);
BEAST_EXPECT(v2.flags() == TapRetry);
PaymentSandbox const v3(&v2);
BEAST_EXPECT(v3.seq() == v2.seq());
BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime());
@@ -1030,7 +1030,7 @@ class View_test : public beast::unit_test::Suite
wipe(*ledger);
ledger->rawInsert(sle(1));
ReadView const& v0 = *ledger;
ApplyViewImpl v1(&v0, ApplyFlags::None);
ApplyViewImpl v1(&v0, TapNone);
{
Sandbox v2(&v1);
v2.erase(v2.peek(k(1)));
+3
View File
@@ -12,6 +12,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTIssue.h>
@@ -180,6 +181,7 @@ public:
auto const result = env.rpc("json", "sign", to_string(req))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Field 'tx_json.Asset' has invalid data.");
}
@@ -253,6 +255,7 @@ public:
auto const result = env.rpc("json", "sign", to_string(req))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Field 'tx_json.Asset' has invalid data.");
}
+29 -1
View File
@@ -8,6 +8,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/TxFlags.h>
@@ -56,12 +57,16 @@ public:
Account const gw("gw");
auto const usd = gw["USD"];
auto const jv = ammAlice.ammRpcInfo({}, {}, usd, usd);
BEAST_EXPECT(jv[jss::error] == "actNotFound");
BEAST_EXPECT(jv[jss::error_code] == RpcActNotFound);
BEAST_EXPECT(jv[jss::error_message] == "Account not found.");
});
// Invalid LP account id
testAMM([&](AMM& ammAlice, Env&) {
auto const jv = ammAlice.ammRpcInfo(bogie.id());
BEAST_EXPECT(jv[jss::error] == "actMalformed");
BEAST_EXPECT(jv[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
});
@@ -69,6 +74,8 @@ public:
testAMM([&](AMM& ammAlice, Env&) {
auto const jv =
ammAlice.ammRpcInfo(json::Value{42}, std::nullopt, XRP, USD, std::nullopt, true, 3);
BEAST_EXPECT(jv[jss::error] == "actMalformed");
BEAST_EXPECT(jv[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
});
@@ -82,6 +89,8 @@ public:
json::Value{42},
false,
3);
BEAST_EXPECT(jv[jss::error] == "actMalformed");
BEAST_EXPECT(jv[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
});
@@ -106,6 +115,8 @@ public:
iss2,
accountId(ammAlice, acct),
ignoreParams);
BEAST_EXPECT(jv[jss::error] == "invalidParams");
BEAST_EXPECT(jv[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
}
});
@@ -121,6 +132,8 @@ public:
iss2,
accountId(ammAlice, acct),
ignoreParams);
BEAST_EXPECT(jv[jss::error] == "invalidParams");
BEAST_EXPECT(jv[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
}
});
@@ -137,6 +150,8 @@ public:
accountId(ammAlice, acct),
ignoreParams,
3);
BEAST_EXPECT(jv[jss::error] == "actMalformed");
BEAST_EXPECT(jv[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
}
});
@@ -145,6 +160,8 @@ public:
testAMM([&](AMM& ammAlice, Env&) {
auto const jv = ammAlice.ammRpcInfo(
std::nullopt, std::nullopt, std::nullopt, std::nullopt, bogie.id());
BEAST_EXPECT(jv[jss::error] == "actMalformed");
BEAST_EXPECT(jv[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jv[jss::error_message] == "Account malformed.");
});
@@ -169,6 +186,8 @@ public:
iss2,
accountId(ammAlice, acct),
ignoreParams);
BEAST_EXPECT(jv[jss::error] == "invalidParams");
BEAST_EXPECT(jv[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters.");
}
});
@@ -185,6 +204,13 @@ public:
accountId(ammAlice, acct),
ignoreParams,
3);
BEAST_EXPECT(
jv[jss::error] ==
(acct == TestAccount::Bogie ? std::string("actMalformed")
: std::string("invalidParams")));
BEAST_EXPECT(
jv[jss::error_code] ==
(acct == TestAccount::Bogie ? RpcActMalformed : RpcInvalidParams));
BEAST_EXPECT(
jv[jss::error_message] ==
(acct == TestAccount::Bogie ? std::string("Account malformed.")
@@ -383,7 +409,9 @@ public:
testAMM([&](AMM& amm, Env&) {
auto const resp = amm.ammRpcInfo(
std::nullopt, jss::validated.cStr(), std::nullopt, std::nullopt, gw_);
BEAST_EXPECT(resp.isMember("error") && resp["error"] == "actNotFound");
BEAST_EXPECT(resp[jss::error] == "actNotFound");
BEAST_EXPECT(resp[jss::error_code] == RpcActNotFound);
BEAST_EXPECT(resp[jss::error_message] == "Account not found.");
});
}
+5
View File
@@ -35,6 +35,7 @@ public:
{
// account_info with no account.
auto const info = env.rpc("json", "account_info", "{ }");
BEAST_EXPECT(info[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(info[jss::result][jss::error_message] == "Missing field 'account'.");
}
@@ -45,6 +46,7 @@ public:
"account_info",
"{\"account\": "
"\"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV\"}");
BEAST_EXPECT(info[jss::result][jss::error] == "actMalformed");
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(info[jss::result][jss::error_message] == "Account malformed.");
BEAST_EXPECT(info[jss::result].isMember(jss::ledger_current_index));
@@ -56,6 +58,7 @@ public:
json::Value params;
params[jss::account] = bogie.human();
auto const info = env.rpc("json", "account_info", to_string(params));
BEAST_EXPECT(info[jss::result][jss::error] == "actNotFound");
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcActNotFound);
BEAST_EXPECT(info[jss::result][jss::error_message] == "Account not found.");
BEAST_EXPECT(info[jss::result][jss::account] == bogie.human());
@@ -65,6 +68,7 @@ public:
{
// Cannot use a seed as account
auto const info = env.rpc("json", "account_info", R"JSON({"account": "foo"})JSON");
BEAST_EXPECT(info[jss::result][jss::error] == "actMalformed");
BEAST_EXPECT(info[jss::result][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(info[jss::result][jss::error_message] == "Account malformed.");
}
@@ -334,6 +338,7 @@ public:
BEAST_EXPECT(info[jss::status] == "error");
BEAST_EXPECT(info[jss::error] == "invalidParams");
BEAST_EXPECT(info[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(info[jss::error_message] == "Invalid parameters.");
BEAST_EXPECT(info.isMember(jss::account_data));
BEAST_EXPECT(info[jss::account_data][sfAccount.jsonName] == alice.human());
BEAST_EXPECT(info.isMember(jss::ledger_current_index));
+26 -1
View File
@@ -55,6 +55,7 @@ public:
{
// account_lines with no account.
auto const lines = env.rpc("json", "account_lines", "{ }");
BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -65,6 +66,7 @@ public:
json::Value params;
params[jss::account] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj";
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "actMalformed");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -118,6 +120,7 @@ public:
json::Value params;
params[jss::account] = alice.human();
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "actNotFound");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcActNotFound);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -161,6 +164,7 @@ public:
params[jss::account] = alice.human();
params[jss::ledger_index] = "nonsense";
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -172,6 +176,7 @@ public:
params[jss::account] = alice.human();
params[jss::ledger_index] = 50000;
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "lgrNotFound");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcLgrNotFound);
BEAST_EXPECT(lines[jss::result][jss::error_message] == "ledgerNotFound");
}
@@ -305,6 +310,7 @@ public:
params[jss::account] = alice.human();
params[jss::peer] = "n9MJkEKHDhy5eTLuHUQeAAjo382frHNbFK4C8hcwN4nwM2SrLdBj";
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "actMalformed");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -344,6 +350,7 @@ public:
params[jss::account] = alice.human();
params[jss::limit] = -1;
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -382,6 +389,7 @@ public:
paramsD[jss::account] = alice.human();
paramsD[jss::marker] = marker;
auto const linesD = env.rpc("json", "account_lines", to_string(paramsD));
BEAST_EXPECT(linesD[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(linesD[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
linesD[jss::result][jss::error_message] ==
@@ -393,6 +401,7 @@ public:
params[jss::account] = alice.human();
params[jss::marker] = true;
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -404,6 +413,7 @@ public:
params[jss::account] = alice.human();
params[jss::marker] = "NOT_A_MARKER";
auto const lines = env.rpc("json", "account_lines", to_string(params));
BEAST_EXPECT(lines[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::result][jss::error_message] ==
@@ -548,7 +558,11 @@ public:
beckyLinesParams[jss::account] = becky.human();
beckyLinesParams[jss::marker] = aliceMarker;
auto const beckyLines = env.rpc("json", "account_lines", to_string(beckyLinesParams));
BEAST_EXPECT(beckyLines[jss::result].isMember(jss::error_message));
BEAST_EXPECT(beckyLines[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(beckyLines[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
beckyLines[jss::result][jss::error_message] ==
rpc::makeError(RpcInvalidParams)[jss::error_message]);
}
void
@@ -616,6 +630,7 @@ public:
linesEndParams[jss::account] = alice.human();
linesEndParams[jss::marker] = linesBeg[jss::result][jss::marker];
auto const linesEnd = env.rpc("json", "account_lines", to_string(linesEndParams));
BEAST_EXPECT(linesEnd[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(linesEnd[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
linesEnd[jss::result][jss::error_message] ==
@@ -914,6 +929,7 @@ public:
request[jss::ripplerpc] = "2.0";
request[jss::id] = 5;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -933,6 +949,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "actMalformed");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -953,6 +970,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "actNotFound");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcActNotFound);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -1025,6 +1043,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -1045,6 +1064,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "lgrNotFound");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcLgrNotFound);
BEAST_EXPECT(lines[jss::error][jss::message] == "ledgerNotFound");
BEAST_EXPECT(lines.isMember(jss::jsonrpc) && lines[jss::jsonrpc] == "2.0");
@@ -1220,6 +1240,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "actMalformed");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -1240,6 +1261,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -1314,6 +1336,7 @@ public:
requestD[jss::id] = 5;
requestD[jss::params] = paramsD;
auto const linesD = env.rpc("json2", to_string(requestD));
BEAST_EXPECT(linesD[jss::error][jss::error] == "invalidParams");
BEAST_EXPECT(linesD[jss::error][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
linesD[jss::error][jss::message] ==
@@ -1334,6 +1357,7 @@ public:
request[jss::id] = 5;
request[jss::params] = params;
auto const lines = env.rpc("json2", to_string(request));
BEAST_EXPECT(lines[jss::error][jss::error] == "invalidParams");
BEAST_EXPECT(lines[jss::error][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
lines[jss::error][jss::message] ==
@@ -1492,6 +1516,7 @@ public:
linesEndRequest[jss::id] = 5;
linesEndRequest[jss::params] = linesEndParams;
auto const linesEnd = env.rpc("json2", to_string(linesEndRequest));
BEAST_EXPECT(linesEnd[jss::error][jss::error] == "invalidParams");
BEAST_EXPECT(linesEnd[jss::error][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
linesEnd[jss::error][jss::message] ==
+37 -3
View File
@@ -140,6 +140,8 @@ public:
{
json::Value const params;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Missing field 'account'.");
}
// test account non-string
@@ -149,6 +151,7 @@ public:
params[jss::account] = param;
auto jrr = env.rpc("json", "account_objects", to_string(params))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'.");
};
@@ -164,6 +167,8 @@ public:
json::Value params;
params[jss::account] = "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "actMalformed");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcActMalformed);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Account malformed.");
}
// test error on account that's not in the ledger.
@@ -171,6 +176,8 @@ public:
json::Value params;
params[jss::account] = Account{"bogie"}.human();
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "actNotFound");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcActNotFound);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Account not found.");
}
Account const bob{"bob"};
@@ -180,6 +187,8 @@ public:
params[jss::account] = bob.human();
params[jss::ledger_index] = 10;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "lgrNotFound");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcLgrNotFound);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "ledgerNotFound");
}
@@ -190,6 +199,8 @@ public:
params[jss::account] = bob.human();
params[jss::type] = 10;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "Invalid field 'type', not string.");
}
@@ -199,6 +210,8 @@ public:
params[jss::account] = bob.human();
params[jss::type] = "expedited";
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'type'.");
}
// test error on limit -ve
@@ -207,6 +220,8 @@ public:
params[jss::account] = bob.human();
params[jss::limit] = -1;
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'limit', not unsigned integer.");
@@ -217,6 +232,8 @@ public:
params[jss::account] = bob.human();
params[jss::sponsored] = "true";
auto resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "Invalid field 'sponsored', not boolean.");
}
@@ -238,27 +255,39 @@ public:
std::string mark = to_string(resumeMarker);
params[jss::marker] = 10;
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
resp[jss::result][jss::error_message] == "Invalid field 'marker', not string.");
params[jss::marker] = "This is a string with no comma";
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = "This string has a comma, but is not hex";
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 64);
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 65);
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 65) + "not hex";
resp = env.rpc("json", "account_objects", to_string(params));
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(resp[jss::result][jss::error_message] == "Invalid field 'marker'.");
// Should this be an error?
@@ -603,7 +632,8 @@ public:
// Make a lambda that checks if the response has error for invalid type
auto const acctObjsTypeIsInvalid = [](json::Value const& resp) {
return resp[jss::result].isMember(jss::error) &&
return resp[jss::result][jss::error] == "invalidParams" &&
resp[jss::result][jss::error_code] == RpcInvalidParams &&
resp[jss::result][jss::error_message] == "Invalid field \'type\'.";
};
@@ -1174,7 +1204,9 @@ public:
params[jss::ledger_index] = jss::validated;
params[jss::marker] = marker;
json::Value const resp = env.rpc("json", "account_nfts", to_string(params));
return resp[jss::result][jss::error_message] == errorMessage;
return resp[jss::result][jss::error] == "invalidParams" &&
resp[jss::result][jss::error_code] == RpcInvalidParams &&
resp[jss::result][jss::error_message] == errorMessage;
};
// test an invalid marker that is not a string
@@ -1427,7 +1459,9 @@ public:
params[jss::ledger_index] = jss::validated;
params[jss::marker] = marker;
json::Value const resp = env.rpc("json", "account_objects", to_string(params));
return resp[jss::result][jss::error_message] == "Invalid field \'marker\'.";
return resp[jss::result][jss::error] == "invalidParams" &&
resp[jss::result][jss::error_code] == RpcInvalidParams &&
resp[jss::result][jss::error_message] == "Invalid field \'marker\'.";
};
auto const markerStr = marker.asString();
+10 -8
View File
@@ -173,7 +173,9 @@ public:
jvParams[jss::limit] = 0u;
auto const jrr =
env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr.isMember(jss::error_message));
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit'.");
}
}
@@ -195,9 +197,9 @@ public:
{
// no account field
auto const jrr = env.rpc("account_offers");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "badSyntax");
BEAST_EXPECT(jrr[jss::error_code] == RpcBadSyntax);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Syntax error.");
}
@@ -226,9 +228,9 @@ public:
jvParams[jss::account] = "";
auto const jrr =
env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "actMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcActMalformed);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Account malformed.");
BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
BEAST_EXPECT(jrr[jss::validated] == false);
@@ -237,9 +239,9 @@ public:
{
// bogus account value
auto const jrr = env.rpc("account_offers", Account("bogus").human())[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "actNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcActNotFound);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Account not found.");
}
@@ -250,9 +252,9 @@ public:
jvParams[jss::limit] = "0"; // NOT an integer
auto const jrr =
env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not unsigned integer.");
}
@@ -263,9 +265,9 @@ public:
jvParams[jss::marker] = "NOT_A_MARKER";
auto const jrr =
env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECTS(
jrr[jss::error_message] == "Invalid field 'marker'.", jrr.toStyledString());
}
@@ -277,9 +279,9 @@ public:
jvParams[jss::marker] = 1;
auto const jrr =
env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not string.");
}
@@ -290,9 +292,9 @@ public:
jvParams[jss::ledger_index] = 10u;
auto const jrr =
env.rpc("json", "account_offers", jvParams.toStyledString())[jss::result];
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcLgrNotFound);
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
}
+129 -62
View File
@@ -195,19 +195,27 @@ class AccountTx_test : public beast::unit_test::Suite
(j[jss::result][jss::transactions].size() == 0);
};
auto const isErr = [](json::Value const& j, ErrorCodeI code) {
return j.isMember(jss::result) && j[jss::result].isMember(jss::error) &&
j[jss::result][jss::error] == rpc::getErrorInfo(code).token;
auto const isErr = [](json::Value const& j, ErrorCodeI code, std::string const& message) {
return j.isMember(jss::result) &&
j[jss::result][jss::error] == rpc::getErrorInfo(code).token &&
j[jss::result][jss::error_code] == code &&
j[jss::result][jss::error_message] == message;
};
json::Value jParams;
jParams[jss::api_version] = apiVersion;
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(jParams)), RpcInvalidParams));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(jParams)),
RpcInvalidParams,
"Missing field 'account'."));
jParams[jss::account] = "0xDEADBEEF";
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(jParams)), RpcActMalformed));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(jParams)),
RpcActMalformed,
"Account malformed."));
jParams[jss::account] = a1.human();
BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(jParams))));
@@ -227,8 +235,10 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(
isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrIdxMalformed));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrIdxMalformed,
"Ledger index malformed."));
}
p[jss::ledger_index_min] = 1;
@@ -239,15 +249,18 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(
isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrIdxMalformed));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrIdxMalformed,
"Ledger index malformed."));
}
p[jss::ledger_index_min] = 2;
p[jss::ledger_index_max] = 1;
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
(apiVersion == 1 ? RpcLgrIdxsInvalid : RpcInvalidLgrRange)));
(apiVersion == 1 ? RpcLgrIdxsInvalid : RpcInvalidLgrRange),
(apiVersion == 1 ? "Ledger indexes invalid." : "Ledger range is invalid.")));
}
// Ledger index min only
{
@@ -262,14 +275,17 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(
isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrIdxMalformed));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrIdxMalformed,
"Ledger index malformed."));
}
p[jss::ledger_index_min] = env.current()->header().seq;
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
(apiVersion == 1 ? RpcLgrIdxsInvalid : RpcInvalidLgrRange)));
(apiVersion == 1 ? RpcLgrIdxsInvalid : RpcInvalidLgrRange),
(apiVersion == 1 ? "Ledger indexes invalid." : "Ledger range is invalid.")));
}
// Ledger index max only
@@ -285,8 +301,10 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(
isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrIdxMalformed));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrIdxMalformed,
"Ledger index malformed."));
}
p[jss::ledger_index_max] = 3;
@@ -310,10 +328,14 @@ class AccountTx_test : public beast::unit_test::Suite
BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
p[jss::ledger_index] = env.current()->header().seq;
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotValidated));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrNotValidated,
"Ledger not validated."));
p[jss::ledger_index] = env.current()->header().seq + 1;
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotFound));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)), RpcLgrNotFound, "ledgerNotFound"));
}
{
@@ -326,10 +348,16 @@ class AccountTx_test : public beast::unit_test::Suite
BEAST_EXPECT(hasTxs(env.rpc(apiVersion, "json", "account_tx", to_string(p))));
p[jss::ledger_index] = "current";
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotValidated));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrNotValidated,
"Ledger not validated."));
p[jss::ledger_index] = "";
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrNotValidated));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrNotValidated,
"Ledger not validated."));
}
// Ledger Hash
@@ -360,7 +388,10 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcInvalidParams));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
"invalidParams"));
}
}
@@ -374,8 +405,10 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(
isErr(env.rpc("json", "account_tx", to_string(p)), RpcLgrIdxMalformed));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcLgrIdxMalformed,
"Ledger index malformed."));
}
}
// test account non-string
@@ -385,6 +418,7 @@ class AccountTx_test : public beast::unit_test::Suite
params[jss::account] = param;
auto jrr = env.rpc("json", "account_tx", to_string(params))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'account'.");
};
@@ -406,7 +440,10 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcInvalidParams));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
"Invalid field 'binary'."));
}
p[jss::binary] = true;
@@ -420,7 +457,10 @@ class AccountTx_test : public beast::unit_test::Suite
}
else
{
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcInvalidParams));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
"Invalid field 'forward'."));
}
p[jss::forward] = false;
@@ -433,70 +473,83 @@ class AccountTx_test : public beast::unit_test::Suite
// Test case: limit = 0 should fail (below minimum)
p[jss::limit] = 0;
BEAST_EXPECT(isErr(env.rpc("json", "account_tx", to_string(p)), RpcInvalidParams));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
"Invalid field 'limit'."));
// Test case: limit = 1.2 should fail (not an integer)
p[jss::limit] = 1.2;
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = "10" should fail (string instead of integer)
p[jss::limit] = "10";
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = true should fail (boolean instead of integer)
p[jss::limit] = true;
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = false should fail (boolean instead of integer)
p[jss::limit] = false;
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = -1 should fail (negative number)
p[jss::limit] = -1;
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = [] should fail (array instead of integer)
p[jss::limit] = json::Value(json::ValueType::Array);
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = {} should fail (object instead of integer)
p[jss::limit] = json::Value(json::ValueType::Object);
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = "malformed" should fail (malformed string)
p[jss::limit] = "malformed";
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = ["limit"] should fail (array with string)
p[jss::limit] = json::Value(json::ValueType::Array);
p[jss::limit].append("limit");
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = {"limit": 10} should fail (object with
// property)
p[jss::limit] = json::Value(json::ValueType::Object);
p[jss::limit][jss::limit] = 10;
BEAST_EXPECT(
env.rpc("json", "account_tx", to_string(p))[jss::result][jss::error_message] ==
rpc::expectedFieldMessage(jss::limit, "unsigned integer"));
BEAST_EXPECT(isErr(
env.rpc("json", "account_tx", to_string(p)),
RpcInvalidParams,
rpc::expectedFieldMessage(jss::limit, "unsigned integer")));
// Test case: limit = 10 should succeed (valid integer)
p[jss::limit] = 10;
@@ -985,12 +1038,16 @@ class AccountTx_test : public beast::unit_test::Suite
};
auto const checkError = [&](json::Value const& delegateParams,
std::string const& errToken) {
std::string const& errToken,
ErrorCodeI code,
std::string const& errMessage) {
json::Value params;
params[jss::account] = alice.human();
params[jss::delegate] = delegateParams;
auto res = env.rpc("json", "account_tx", to_string(params));
BEAST_EXPECT(res[jss::result][jss::error] == errToken);
BEAST_EXPECT(res[jss::result][jss::error_code] == code);
BEAST_EXPECT(res[jss::result][jss::error_message] == errMessage);
};
// Filter: Delegatee. Expects TX #2 (Signed by Bob)
@@ -1061,27 +1118,27 @@ class AccountTx_test : public beast::unit_test::Suite
// "delegate" is not an object (e.g., string)
{
json::Value const p = "not_an_object";
checkError(p, "invalidParams");
checkError(p, "invalidParams", RpcInvalidParams, "Invalid field 'delegate'.");
}
// Missing "delegate_filter" inside object
{
json::Value const p(json::ValueType::Object);
checkError(p, "invalidParams");
checkError(p, "invalidParams", RpcInvalidParams, "Invalid field 'delegate_filter'.");
}
// "delegate_filter" is not a string (e.g., int)
{
json::Value p;
p[jss::delegate_filter] = 123;
checkError(p, "invalidParams");
checkError(p, "invalidParams", RpcInvalidParams, "Invalid field 'delegate_filter'.");
}
// "delegate_filter" has invalid value
{
json::Value p;
p[jss::delegate_filter] = "random_string";
checkError(p, "invalidParams");
checkError(p, "invalidParams", RpcInvalidParams, "Invalid field 'delegate_filter'.");
}
// "counterparty" is not a string
@@ -1089,7 +1146,7 @@ class AccountTx_test : public beast::unit_test::Suite
json::Value p;
p[jss::delegate_filter] = "actor";
p[jss::counter_party] = 123;
checkError(p, "invalidParams");
checkError(p, "invalidParams", RpcInvalidParams, "Invalid field 'counter_party'.");
}
// "counterparty" is malformed base58
@@ -1097,7 +1154,7 @@ class AccountTx_test : public beast::unit_test::Suite
json::Value p;
p[jss::delegate_filter] = "actor";
p[jss::counter_party] = "not_an_account";
checkError(p, "actMalformed");
checkError(p, "actMalformed", RpcActMalformed, "Account malformed.");
}
// Multi-signed non-delegated TX: Alice pays Carol via multi-sig.
@@ -1181,6 +1238,11 @@ class AccountTx_test : public beast::unit_test::Suite
p[jss::marker] = delegateMarker;
auto const r = env.rpc("json", "account_tx", to_string(p));
BEAST_EXPECT(r[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(r[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
r[jss::result][jss::error_message] ==
"Do not mix delegate and non-delegate pagination markers in account_tx; "
"repeat the same `delegate` object when using a delegate marker.");
}
// Obtain a non-delegate marker; it must not carry the flag.
@@ -1205,6 +1267,11 @@ class AccountTx_test : public beast::unit_test::Suite
p[jss::marker] = normalMarker;
auto const r = env.rpc("json", "account_tx", to_string(p));
BEAST_EXPECT(r[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(r[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
r[jss::result][jss::error_message] ==
"Do not mix delegate and non-delegate pagination markers in account_tx; "
"repeat the same `delegate` object when using a delegate marker.");
}
}
}
+19 -6
View File
@@ -14,6 +14,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/config/Constants.h>
#include <xrpl/json/to_string.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/KeyType.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/jss.h>
@@ -186,32 +187,42 @@ class AmendmentBlocked_test : public beast::unit_test::Suite
// ledger_accept
jr = env.rpc("ledger_accept")[jss::result];
BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::status] == "error");
BEAST_EXPECT(jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error_code] == RpcAmendmentBlocked);
BEAST_EXPECT(jr[jss::error_message] == "Amendment blocked, need upgrade.");
BEAST_EXPECT(!jr.isMember(jss::warnings));
// ledger_current
jr = env.rpc("ledger_current")[jss::result];
BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::status] == "error");
BEAST_EXPECT(jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error_code] == RpcAmendmentBlocked);
BEAST_EXPECT(jr[jss::error_message] == "Amendment blocked, need upgrade.");
BEAST_EXPECT(!jr.isMember(jss::warnings));
// owner_info
jr = env.rpc("owner_info", alice.human())[jss::result];
BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::status] == "error");
BEAST_EXPECT(jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error_code] == RpcAmendmentBlocked);
BEAST_EXPECT(jr[jss::error_message] == "Amendment blocked, need upgrade.");
BEAST_EXPECT(!jr.isMember(jss::warnings));
// path_find
jr = wsc->invoke("path_find", pfReq)[jss::result];
BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::status] == "error");
BEAST_EXPECT(jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error_code] == RpcAmendmentBlocked);
BEAST_EXPECT(jr[jss::error_message] == "Amendment blocked, need upgrade.");
BEAST_EXPECT(!jr.isMember(jss::warnings));
// submit
jr = env.rpc("submit", strHex(s.slice()))[jss::result];
BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::status] == "error");
BEAST_EXPECT(jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error_code] == RpcAmendmentBlocked);
BEAST_EXPECT(jr[jss::error_message] == "Amendment blocked, need upgrade.");
BEAST_EXPECT(!jr.isMember(jss::warnings));
// submit_multisigned
@@ -221,7 +232,9 @@ class AmendmentBlocked_test : public beast::unit_test::Suite
BEAST_EXPECT(jr[jss::status] == "success");
msReq[jss::tx_json] = jr[jss::tx_json];
jr = env.rpc("json", "submit_multisigned", to_string(msReq))[jss::result];
BEAST_EXPECT(jr.isMember(jss::error) && jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error] == "amendmentBlocked");
BEAST_EXPECT(jr[jss::error_code] == RpcAmendmentBlocked);
BEAST_EXPECT(jr[jss::error_message] == "Amendment blocked, need upgrade.");
BEAST_EXPECT(!jr.isMember(jss::warnings));
}
+7 -2
View File
@@ -19,6 +19,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/Ledger.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
@@ -77,8 +78,12 @@ public:
// non-conventional ledger input should throw an error
params["ledger"] = "non_conventional_ledger_input";
resp = env.rpc("json", "book_changes", to_string(params));
BEAST_EXPECT(resp[jss::result].isMember(jss::error));
BEAST_EXPECT(resp[jss::result][jss::status] != "success");
BEAST_EXPECT(resp[jss::result][jss::status] == "error");
BEAST_EXPECT(resp[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(resp[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'ledger', not string or number.");
}
void
+28
View File
@@ -20,6 +20,7 @@
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -1225,6 +1226,7 @@ public:
jvParams[jss::ledger_index] = 10u;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcLgrNotFound);
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
}
@@ -1233,6 +1235,7 @@ public:
jvParams[jss::ledger_index] = "validated";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_pays'.");
}
@@ -1242,6 +1245,7 @@ public:
jvParams[jss::taker_pays] = json::ValueType::Object;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_gets'.");
}
@@ -1252,6 +1256,7 @@ public:
jvParams[jss::taker_gets] = json::ValueType::Object;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_pays', not object.");
}
@@ -1262,6 +1267,7 @@ public:
jvParams[jss::taker_gets] = "not an object";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker_gets', not object.");
}
@@ -1272,6 +1278,7 @@ public:
jvParams[jss::taker_gets] = json::ValueType::Object;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_pays.currency'.");
}
@@ -1282,6 +1289,7 @@ public:
jvParams[jss::taker_gets] = json::ValueType::Object;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_pays.currency', not string.");
}
@@ -1293,6 +1301,7 @@ public:
jvParams[jss::taker_gets] = json::ValueType::Object;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Missing field 'taker_gets.currency'.");
}
@@ -1303,6 +1312,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = 1;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_gets.currency', not string.");
}
@@ -1314,6 +1324,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = "XRP";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "srcCurMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcCurMalformed);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_pays.currency', bad currency.");
}
@@ -1325,6 +1336,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = "NOT_VALID";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "dstAmtMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcDstAmtMalformed);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_gets.currency', bad currency.");
}
@@ -1337,6 +1349,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = 1;
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_gets.issuer', not string.");
}
@@ -1349,6 +1362,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = "USD";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_pays.issuer', not string.");
}
@@ -1361,6 +1375,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = "USD";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_pays.issuer', bad issuer.");
}
@@ -1373,6 +1388,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = "USD";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] ==
"Invalid field 'taker_pays.issuer', bad issuer account one.");
@@ -1386,6 +1402,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human() + "DEAD";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcDstIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] == "Invalid field 'taker_gets.issuer', bad issuer.");
}
@@ -1398,6 +1415,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = toBase58(noAccount());
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcDstIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] ==
"Invalid field 'taker_gets.issuer', bad issuer account one.");
@@ -1412,6 +1430,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] ==
"Unneeded field 'taker_pays.issuer' "
@@ -1427,6 +1446,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "srcIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcSrcIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] ==
"Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
@@ -1441,6 +1461,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker', not string.");
}
@@ -1453,6 +1474,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'taker'.");
}
@@ -1466,6 +1488,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "badMarket");
BEAST_EXPECT(jrr[jss::error_code] == RpcBadMarket);
BEAST_EXPECT(jrr[jss::error_message] == "No such market.");
}
@@ -1479,6 +1502,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not unsigned integer.");
}
@@ -1492,6 +1516,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit'.");
}
@@ -1503,6 +1528,7 @@ public:
jvParams[jss::taker_gets][jss::currency] = "USD";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcDstIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] ==
"Invalid field 'taker_gets.issuer', "
@@ -1518,6 +1544,7 @@ public:
jvParams[jss::taker_gets][jss::issuer] = gw.human();
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "dstIsrMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcDstIsrMalformed);
BEAST_EXPECT(
jrr[jss::error_message] ==
"Unneeded field 'taker_gets.issuer' "
@@ -1533,6 +1560,7 @@ public:
jvParams[jss::domain] = "badString";
auto const jrr = env.rpc("json", "book_offers", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "domainMalformed");
BEAST_EXPECT(jrr[jss::error_code] == RpcDomainMalformed);
BEAST_EXPECT(jrr[jss::error_message] == "Unable to parse domain.");
}
}
+2 -1
View File
@@ -2,6 +2,7 @@
#include <test/jtx/Env.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/jss.h>
namespace xrpl {
@@ -22,8 +23,8 @@ class Connect_test : public beast::unit_test::Suite
auto const result = env.rpc("json", "connect", "{}");
BEAST_EXPECT(result[jss::result][jss::status] == "error");
BEAST_EXPECT(result[jss::result].isMember(jss::error));
BEAST_EXPECT(result[jss::result][jss::error] == "notSynced");
BEAST_EXPECT(result[jss::result][jss::error_code] == RpcNotSynced);
BEAST_EXPECT(result[jss::result][jss::error_message] == "Not synced to the network.");
}
}
+119 -29
View File
@@ -8,6 +8,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Protocol.h> // IWYU pragma: keep
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/TxFlags.h>
@@ -154,12 +155,16 @@ public:
Account const becky{"becky"};
// Lambda that checks the (error) result of deposit_authorized.
auto const verifyErr =
[this](json::Value const& result, char const* error, char const* errorMsg) {
BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
BEAST_EXPECT(result[jss::result][jss::error] == error);
BEAST_EXPECT(result[jss::result][jss::error_message] == errorMsg);
};
auto const verifyErr = [this](
json::Value const& result,
char const* error,
ErrorCodeI code,
char const* errorMsg) {
BEAST_EXPECT(result[jss::result][jss::status] == jss::error);
BEAST_EXPECT(result[jss::result][jss::error] == error);
BEAST_EXPECT(result[jss::result][jss::error_code] == code);
BEAST_EXPECT(result[jss::result][jss::error_message] == errorMsg);
};
Env env(*this);
{
@@ -167,28 +172,33 @@ public:
json::Value args{depositAuthArgs(alice, becky)};
args.removeMember(jss::source_account);
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "invalidParams", "Missing field 'source_account'.");
verifyErr(result, "invalidParams", RpcInvalidParams, "Missing field 'source_account'.");
}
{
// Non-string source_account field.
json::Value args{depositAuthArgs(alice, becky)};
args[jss::source_account] = 7.3;
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "invalidParams", "Invalid field 'source_account', not a string.");
verifyErr(
result,
"invalidParams",
RpcInvalidParams,
"Invalid field 'source_account', not a string.");
}
{
// Corrupt source_account field.
json::Value args{depositAuthArgs(alice, becky)};
args[jss::source_account] = "rG1QQv2nh2gr7RCZ!P8YYcBUKCCN633jCn";
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "actMalformed", "Account malformed.");
verifyErr(result, "actMalformed", RpcActMalformed, "Account malformed.");
}
{
// Missing destination_account field.
json::Value args{depositAuthArgs(alice, becky)};
args.removeMember(jss::destination_account);
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "invalidParams", "Missing field 'destination_account'.");
verifyErr(
result, "invalidParams", RpcInvalidParams, "Missing field 'destination_account'.");
}
{
// Non-string destination_account field.
@@ -196,40 +206,46 @@ public:
args[jss::destination_account] = 7.3;
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(
result, "invalidParams", "Invalid field 'destination_account', not a string.");
result,
"invalidParams",
RpcInvalidParams,
"Invalid field 'destination_account', not a string.");
}
{
// Corrupt destination_account field.
json::Value args{depositAuthArgs(alice, becky)};
args[jss::destination_account] = "rP6P9ypfAmc!pw8SZHNwM4nvZHFXDraQas";
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "actMalformed", "Account malformed.");
verifyErr(result, "actMalformed", RpcActMalformed, "Account malformed.");
}
{
// Request an invalid ledger.
json::Value const args{depositAuthArgs(alice, becky, "-1")};
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(
result, "invalidParams", "Invalid field 'ledger_index', not string or number.");
result,
"invalidParams",
RpcInvalidParams,
"Invalid field 'ledger_index', not string or number.");
}
{
// Request a ledger that doesn't exist yet as a string.
json::Value const args{depositAuthArgs(alice, becky, "17")};
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "lgrNotFound", "ledgerNotFound");
verifyErr(result, "lgrNotFound", RpcLgrNotFound, "ledgerNotFound");
}
{
// Request a ledger that doesn't exist yet.
json::Value args{depositAuthArgs(alice, becky)};
args[jss::ledger_index] = 17;
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "lgrNotFound", "ledgerNotFound");
verifyErr(result, "lgrNotFound", RpcLgrNotFound, "ledgerNotFound");
}
{
// alice is not yet funded.
json::Value const args{depositAuthArgs(alice, becky)};
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "srcActNotFound", "Source account not found.");
verifyErr(result, "srcActNotFound", RpcSrcActNotFound, "Source account not found.");
}
env.fund(XRP(1000), alice);
env.close();
@@ -237,7 +253,8 @@ public:
// becky is not yet funded.
json::Value const args{depositAuthArgs(alice, becky)};
json::Value const result{env.rpc("json", "deposit_authorized", args.toStyledString())};
verifyErr(result, "dstActNotFound", "Destination account not found.");
verifyErr(
result, "dstActNotFound", RpcDstActNotFound, "Destination account not found.");
}
env.fund(XRP(1000), becky);
env.close();
@@ -256,9 +273,11 @@ public:
jtx::Account const& dst,
bool authorized,
std::vector<std::string> credentialIDs = {},
std::string_view error = "")
std::string_view error = "",
ErrorCodeI code = RpcSuccess,
std::string_view errorMessage = "")
{
BEAST_EXPECT(result[jss::status] == authorized ? jss::success : jss::error);
BEAST_EXPECT(result[jss::status] == (authorized ? jss::success : jss::error));
if (result.isMember(jss::deposit_authorized))
BEAST_EXPECT(result[jss::deposit_authorized] == authorized);
if (authorized)
@@ -270,7 +289,11 @@ public:
BEAST_EXPECT(result.isMember(jss::error) == !error.empty());
if (!error.empty())
{
BEAST_EXPECT(result[jss::error].asString() == error);
BEAST_EXPECT(result[jss::error_code] == code);
BEAST_EXPECT(result[jss::error_message].asString() == errorMessage);
}
if (authorized)
{
@@ -334,7 +357,15 @@ public:
args[jss::credentials] = json::ValueType::Array;
auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString());
checkCredentialsResponse(jv[jss::result], alice, becky, false, {}, "invalidParams");
checkCredentialsResponse(
jv[jss::result],
alice,
becky,
false,
{},
"invalidParams",
RpcInvalidParams,
"Invalid field 'credentials', not is non-empty array of CredentialID(hash256).");
}
{
@@ -348,7 +379,15 @@ public:
args[jss::credentials].append(3);
auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString());
checkCredentialsResponse(jv[jss::result], alice, becky, false, {}, "invalidParams");
checkCredentialsResponse(
jv[jss::result],
alice,
becky,
false,
{},
"invalidParams",
RpcInvalidParams,
"Invalid field 'credentials', not an array of CredentialID(hash256).");
}
{
@@ -362,7 +401,14 @@ public:
auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString());
checkCredentialsResponse(
jv[jss::result], alice, becky, false, {"hello world"}, "invalidParams");
jv[jss::result],
alice,
becky,
false,
{"hello world"},
"invalidParams",
RpcInvalidParams,
"Invalid field 'credentials', not an array of CredentialID(hash256).");
}
{
@@ -389,7 +435,9 @@ public:
"0127AB8B4B29CCDBB61AA51C0799A8A6BB80B86A9899807C11ED576AF8516"
"473",
},
"badCredentials");
"badCredentials",
RpcBadCredentials,
"credentials don't exist");
}
{
@@ -403,7 +451,14 @@ public:
auto const jv = env.rpc("json", "deposit_authorized", args.toStyledString());
checkCredentialsResponse(
jv[jss::result], alice, becky, false, {zero}, "badCredentials");
jv[jss::result],
alice,
becky,
false,
{zero},
"badCredentials",
RpcBadCredentials,
"credentials don't exist");
}
}
@@ -416,7 +471,14 @@ public:
"deposit_authorized",
depositAuthArgs(alice, becky, "validated", {credIdx}).toStyledString());
checkCredentialsResponse(
jv[jss::result], alice, becky, false, {credIdx}, "badCredentials");
jv[jss::result],
alice,
becky,
false,
{credIdx},
"badCredentials",
RpcBadCredentials,
"credentials aren't accepted");
}
// alice accept credentials
@@ -430,7 +492,14 @@ public:
"deposit_authorized",
depositAuthArgs(alice, becky, "validated", {credIdx, credIdx}).toStyledString());
checkCredentialsResponse(
jv[jss::result], alice, becky, false, {credIdx, credIdx}, "badCredentials");
jv[jss::result],
alice,
becky,
false,
{credIdx, credIdx},
"badCredentials",
RpcBadCredentials,
"duplicates in credentials");
}
{
@@ -453,7 +522,14 @@ public:
"deposit_authorized",
depositAuthArgs(alice, becky, "validated", kCredIds).toStyledString());
checkCredentialsResponse(
jv[jss::result], alice, becky, false, kCredIds, "invalidParams");
jv[jss::result],
alice,
becky,
false,
kCredIds,
"invalidParams",
RpcInvalidParams,
"Invalid field 'credentials', not array too long.");
}
{
@@ -500,7 +576,14 @@ public:
"deposit_authorized",
depositAuthArgs(becky, alice, "validated", {credDiana}).toStyledString());
checkCredentialsResponse(
jv[jss::result], becky, alice, false, {credDiana}, "badCredentials");
jv[jss::result],
becky,
alice,
false,
{credDiana},
"badCredentials",
RpcBadCredentials,
"credentials doesn't belong to the root account");
}
{
@@ -549,7 +632,14 @@ public:
depositAuthArgs(alice, becky, "validated", {credIdx2}).toStyledString());
checkCredentialsResponse(
jv[jss::result], alice, becky, false, {credIdx2}, "badCredentials");
jv[jss::result],
alice,
becky,
false,
{credIdx2},
"badCredentials",
RpcBadCredentials,
"credentials are expired");
}
}
}
+9
View File
@@ -11,6 +11,7 @@
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/AmendmentTable.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/digest.h>
#include <xrpl/protocol/jss.h>
@@ -206,6 +207,7 @@ class Feature_test : public beast::unit_test::Suite
// feature names are case-sensitive - expect error here
jrr = env.rpc("feature", "fMM")[jss::result];
BEAST_EXPECT(jrr[jss::error] == "badFeature");
BEAST_EXPECT(jrr[jss::error_code] == RpcBadFeature);
BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid.");
// Test feature name size checks
@@ -253,6 +255,7 @@ class Feature_test : public beast::unit_test::Suite
params[jss::feature] = param;
auto jrr = env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
};
@@ -266,6 +269,7 @@ class Feature_test : public beast::unit_test::Suite
{
auto jrr = env.rpc("feature", "AllTheThings")[jss::result];
BEAST_EXPECT(jrr[jss::error] == "badFeature");
BEAST_EXPECT(jrr[jss::error_code] == RpcBadFeature);
BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid.");
}
}
@@ -320,6 +324,7 @@ class Feature_test : public beast::unit_test::Suite
"EF";
auto const result = env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECTS(result[jss::error] == "badFeature", result.toStyledString());
BEAST_EXPECT(result[jss::error_code] == RpcBadFeature);
BEAST_EXPECT(result[jss::error_message] == "Feature unknown or invalid.");
}
@@ -332,6 +337,7 @@ class Feature_test : public beast::unit_test::Suite
params[jss::vetoed] = true;
auto const result = env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECTS(result[jss::error] == "noPermission", result[jss::error].asString());
BEAST_EXPECT(result[jss::error_code] == RpcNoPermission);
BEAST_EXPECT(
result[jss::error_message] == "You don't have permission for this command.");
}
@@ -513,6 +519,7 @@ class Feature_test : public beast::unit_test::Suite
auto const result = env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid parameters.");
};
@@ -521,6 +528,7 @@ class Feature_test : public beast::unit_test::Suite
// anything other than accept or reject is an error
jrr = env.rpc("feature", kFeatureName, "maybe");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
}
@@ -584,6 +592,7 @@ class Feature_test : public beast::unit_test::Suite
// anything other than accept or reject is an error
jrr = env.rpc("feature", featureName, "maybe");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
}
+10
View File
@@ -10,6 +10,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ApiVersion.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/TxFlags.h>
@@ -172,7 +173,12 @@ public:
auto response = jv[jss::result];
auto const error = apiVersion < 2u ? "invalidHotWallet" : "invalidParams";
auto const errorCode = apiVersion < 2u ? RpcInvalidHotwallet : RpcInvalidParams;
auto const errorMessage =
apiVersion < 2u ? "Invalid hotwallet." : "Invalid parameters.";
BEAST_EXPECT(response[jss::error] == error);
BEAST_EXPECT(response[jss::error_code] == errorCode);
BEAST_EXPECT(response[jss::error_message] == errorMessage);
});
}
@@ -201,6 +207,8 @@ public:
auto jv = wsc->invoke("gateway_balances", qry);
expect(jv[jss::status] == "error");
BEAST_EXPECT(jv[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jv[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jv[jss::result][jss::error_message] == "Invalid field 'account'.");
});
// The same applies to a non-string "ident".
@@ -212,6 +220,8 @@ public:
auto jv = wsc->invoke("gateway_balances", qry2);
expect(jv[jss::status] == "error");
BEAST_EXPECT(jv[jss::result][jss::error] == "invalidParams");
BEAST_EXPECT(jv[jss::result][jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jv[jss::result][jss::error_message] == "Invalid field 'ident'.");
});
}
+41
View File
@@ -12,6 +12,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/OpenView.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
@@ -42,10 +43,14 @@ public:
auto const baseFee = env.current()->fees().base;
// missing base_asset
auto ret = Oracle::aggregatePrice(env, std::nullopt, "USD", kOracles);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Missing field 'base_asset'.");
// missing quote_asset
ret = Oracle::aggregatePrice(env, "XRP", std::nullopt, kOracles);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Missing field 'quote_asset'.");
// invalid base_asset, quote_asset
@@ -69,28 +74,44 @@ public:
{
ret = Oracle::aggregatePrice(env, "USD", v, kOracles);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Invalid parameters.");
ret = Oracle::aggregatePrice(env, v, "USD", kOracles);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Invalid parameters.");
ret = Oracle::aggregatePrice(env, v, v, kOracles);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Invalid parameters.");
}
// missing oracles array
ret = Oracle::aggregatePrice(env, "XRP", "USD");
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Missing field 'oracles'.");
// empty oracles array
ret = Oracle::aggregatePrice(env, "XRP", "USD", OraclesData{});
BEAST_EXPECT(ret[jss::error].asString() == "oracleMalformed");
BEAST_EXPECT(ret[jss::error_code] == RpcOracleMalformed);
BEAST_EXPECT(ret[jss::error_message].asString() == "Oracle request is malformed.");
// no token pairs found
ret = Oracle::aggregatePrice(env, "YAN", "USD", kOracles);
BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound");
BEAST_EXPECT(ret[jss::error_code] == RpcObjectNotFound);
BEAST_EXPECT(
ret[jss::error_message].asString() == "The requested object was not found.");
// invalid oracle document id
// id doesn't exist
ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, 2}}});
BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound");
BEAST_EXPECT(ret[jss::error_code] == RpcObjectNotFound);
BEAST_EXPECT(
ret[jss::error_message].asString() == "The requested object was not found.");
// invalid values
std::vector<AnyValue> const invalidDocument = {kNoneTag, 1.2, -1, "", "none", "1.2"};
for (auto const& v : invalidDocument)
@@ -99,17 +120,26 @@ public:
json::Value jv;
toJson(jv, v);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Invalid parameters.");
}
// missing document id
ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, std::nullopt}}});
BEAST_EXPECT(ret[jss::error].asString() == "oracleMalformed");
BEAST_EXPECT(ret[jss::error_code] == RpcOracleMalformed);
BEAST_EXPECT(ret[jss::error_message].asString() == "Oracle request is malformed.");
// invalid owner
ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{some, 1}}});
BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound");
BEAST_EXPECT(ret[jss::error_code] == RpcObjectNotFound);
BEAST_EXPECT(
ret[jss::error_message].asString() == "The requested object was not found.");
// missing account
ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{std::nullopt, 1}}});
BEAST_EXPECT(ret[jss::error].asString() == "oracleMalformed");
BEAST_EXPECT(ret[jss::error_code] == RpcOracleMalformed);
BEAST_EXPECT(ret[jss::error_message].asString() == "Oracle request is malformed.");
// oracles have wrong asset pair
env.fund(XRP(1'000), owner);
@@ -122,6 +152,9 @@ public:
});
ret = Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, oracle.documentID()}}});
BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound");
BEAST_EXPECT(ret[jss::error_code] == RpcObjectNotFound);
BEAST_EXPECT(
ret[jss::error_message].asString() == "The requested object was not found.");
// invalid trim value
std::vector<AnyValue> const invalidTrim = {kNoneTag, 0, 26, -1, 1.2, "", "none", "1.2"};
@@ -130,6 +163,8 @@ public:
ret =
Oracle::aggregatePrice(env, "XRP", "USD", {{{owner, oracle.documentID()}}}, v);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Invalid parameters.");
}
// invalid time threshold value
@@ -139,6 +174,8 @@ public:
ret = Oracle::aggregatePrice(
env, "XRP", "USD", {{{owner, oracle.documentID()}}}, std::nullopt, v);
BEAST_EXPECT(ret[jss::error].asString() == "invalidParams");
BEAST_EXPECT(ret[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(ret[jss::error_message].asString() == "Invalid parameters.");
}
}
@@ -157,6 +194,8 @@ public:
}
auto const ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles);
BEAST_EXPECT(ret[jss::error].asString() == "oracleMalformed");
BEAST_EXPECT(ret[jss::error_code] == RpcOracleMalformed);
BEAST_EXPECT(ret[jss::error_message].asString() == "Oracle request is malformed.");
}
}
@@ -457,6 +496,8 @@ public:
// a nullptr dereference.
auto const ret = Oracle::aggregatePrice(env, "XRP", "USD", oracles);
BEAST_EXPECT(ret[jss::error].asString() == "objectNotFound");
BEAST_EXPECT(ret[jss::error_code] == RpcObjectNotFound);
BEAST_EXPECT(ret[jss::error_message].asString() == "The requested object was not found.");
}
void
File diff suppressed because it is too large. Load diff
+72 -34
View File
@@ -209,7 +209,12 @@ public:
params[jss::seed_hex] = strings.masterSeedHex;
// Secret fields are mutually exclusive.
BEAST_EXPECT(containsError(walletPropose(params)));
auto const result = walletPropose(params);
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
result[jss::error_message] ==
"Exactly one of the following must be specified: passphrase, seed or seed_hex");
}
void
@@ -223,7 +228,8 @@ public:
params[jss::key_type] = "secp256k1";
params[jss::passphrase] = 20160506;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid field 'passphrase', not string.");
}
@@ -232,7 +238,8 @@ public:
params[jss::key_type] = "secp256k1";
params[jss::seed] = json::ValueType::Object;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid field 'seed', not string.");
}
@@ -241,7 +248,8 @@ public:
params[jss::key_type] = "ed25519";
params[jss::seed_hex] = json::ValueType::Array;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid field 'seed_hex', not string.");
}
@@ -253,7 +261,8 @@ public:
params[jss::seed_hex] = common::gMasterSeedHex;
params[jss::seed] = common::gMasterSeed;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
result[jss::error_message] ==
"Exactly one of the following must be specified: passphrase, "
@@ -266,7 +275,8 @@ public:
params[jss::key_type] = "prime256v1";
params[jss::passphrase] = common::gMasterKey;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid parameters.");
}
@@ -275,7 +285,8 @@ public:
params[jss::key_type] = json::ValueType::Object;
params[jss::seed_hex] = common::gMasterSeedHex;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid field 'key_type', not string.");
}
@@ -284,7 +295,8 @@ public:
params[jss::key_type] = json::ValueType::Array;
params[jss::seed] = common::gMasterSeed;
auto result = walletPropose(params);
BEAST_EXPECT(containsError(result));
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(result[jss::error_message] == "Invalid field 'key_type', not string.");
}
}
@@ -402,8 +414,9 @@ public:
json::Value error;
params[jss::secret] = 314159265;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'secret', not string.");
}
@@ -414,8 +427,9 @@ public:
params[jss::secret].append("array:0");
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'secret', not string.");
}
@@ -427,8 +441,9 @@ public:
params[jss::secret]["number"] = 702;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'secret', not string.");
}
@@ -440,8 +455,9 @@ public:
params[jss::secret] = common::gMasterSeed;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(
error[jss::error_message] ==
"The secret field is not allowed if key_type is used.");
@@ -455,8 +471,9 @@ public:
params[jss::passphrase] = common::gMasterKey;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'key_type'.");
}
@@ -467,8 +484,9 @@ public:
params[jss::seed_hex] = common::gMasterSeedHex;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'key_type', not string.");
}
@@ -479,8 +497,9 @@ public:
params[jss::seed] = common::gMasterSeed;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'key_type', not string.");
}
@@ -492,8 +511,9 @@ public:
params[jss::passphrase] = 1234567890;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'passphrase', not string.");
}
@@ -504,8 +524,9 @@ public:
params[jss::passphrase] = json::ValueType::Object;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'passphrase', not string.");
}
@@ -516,8 +537,9 @@ public:
params[jss::passphrase] = json::ValueType::Array;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'passphrase', not string.");
}
@@ -528,8 +550,9 @@ public:
params[jss::passphrase] = "";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -541,8 +564,9 @@ public:
params[jss::seed] = 443556;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed', not string.");
}
@@ -553,8 +577,9 @@ public:
params[jss::seed] = json::ValueType::Object;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed', not string.");
}
@@ -565,8 +590,9 @@ public:
params[jss::seed] = json::ValueType::Array;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed', not string.");
}
@@ -577,8 +603,9 @@ public:
params[jss::seed] = "";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -589,8 +616,9 @@ public:
params[jss::seed] = "s M V s h z D F p t Z E m h s";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -601,8 +629,9 @@ public:
params[jss::seed] = "pnnjkbnobnml43679nbvjdsklnbjs";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -614,8 +643,9 @@ public:
params[jss::seed_hex] = 443556;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed_hex', not string.");
}
@@ -626,8 +656,9 @@ public:
params[jss::seed_hex] = json::ValueType::Object;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed_hex', not string.");
}
@@ -638,8 +669,9 @@ public:
params[jss::seed_hex] = json::ValueType::Array;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "invalidParams");
BEAST_EXPECT(error[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(error[jss::error_message] == "Invalid field 'seed_hex', not string.");
}
@@ -650,8 +682,9 @@ public:
params[jss::seed_hex] = "";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -662,8 +695,9 @@ public:
params[jss::seed_hex] = "A670A19B";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -674,8 +708,9 @@ public:
params[jss::seed_hex] = common::gPassphrase;
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
@@ -686,8 +721,9 @@ public:
params[jss::seed_hex] = "BE6A670A19B209E112146D0A7ED2AAD72567D0FC913";
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(!ret);
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(error[jss::error_message] == "Disallowed seed.");
}
}
@@ -723,7 +759,8 @@ public:
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(
error[jss::error_message] == "Specified seed is for an Ed25519 wallet.");
}
@@ -754,7 +791,8 @@ public:
auto const ret = keypairForSignature(params, error);
BEAST_EXPECT(containsError(error));
BEAST_EXPECT(error[jss::error] == "badSeed");
BEAST_EXPECT(error[jss::error_code] == RpcBadSeed);
BEAST_EXPECT(
error[jss::error_message] == "Specified seed is for an Ed25519 wallet.");
}
+12 -6
View File
@@ -17,6 +17,7 @@
#include <xrpl/json/json_value.h>
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/Serializer.h>
@@ -131,8 +132,9 @@ public:
json::Value jvParams;
jvParams[jss::limit] = "0"; // NOT an integer
auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'limit', not integer.");
}
@@ -141,8 +143,9 @@ public:
json::Value jvParams;
jvParams[jss::marker] = "NOT_A_MARKER";
auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid.");
}
@@ -151,8 +154,9 @@ public:
json::Value jvParams;
jvParams[jss::marker] = 1;
auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'marker', not valid.");
}
@@ -161,8 +165,9 @@ public:
json::Value jvParams;
jvParams[jss::ledger_index] = 10u;
auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::error_code] == RpcLgrNotFound);
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
}
@@ -171,8 +176,9 @@ public:
json::Value jvParams;
jvParams[jss::binary] = "true";
auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_code] == RpcInvalidParams);
BEAST_EXPECT(jrr[jss::error_message] == "Invalid field 'binary', not boolean.");
}
}
@@ -459,8 +465,8 @@ public:
jvParams[jss::ledger_index] = "current";
jvParams[jss::type] = "misspelling";
auto const jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember("error"));
BEAST_EXPECT(jrr["error"] == "invalidParams");
BEAST_EXPECT(jrr["error_code"] == RpcInvalidParams);
BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'.");
}
}
+179 -54
View File
@@ -153,6 +153,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
json::Value const& jv,
std::string const& err,
ErrorCodeI code,
std::string const& msg,
std::source_location const location = std::source_location::current())
{
@@ -165,6 +166,14 @@ class LedgerEntry_test : public beast::unit_test::Suite
"Expected error " + err + ", received " + jv[jss::error].asString() + ", at line " +
std::to_string(location.line()) + ", " + jv.toStyledString());
}
if (BEAST_EXPECT(jv.isMember(jss::error_code)))
{
BEAST_EXPECTS(
jv[jss::error_code] == code,
"Expected error code " + std::to_string(code) + ", received " +
jv[jss::error_code].asString() + ", at line " +
std::to_string(location.line()) + ", " + jv.toStyledString());
}
if (msg.empty())
{
BEAST_EXPECTS(
@@ -340,12 +349,21 @@ class LedgerEntry_test : public beast::unit_test::Suite
apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result];
if (apiVersion < 2u)
{
checkErrorValue(jrr, "unknownOption", "", location);
BEAST_EXPECTS(jrr[jss::status] == "error", std::to_string(location.line()));
BEAST_EXPECTS(
jrr[jss::error] == "unknownOption", std::to_string(location.line()));
BEAST_EXPECTS(!jrr.isMember(jss::error_code), std::to_string(location.line()));
BEAST_EXPECTS(
jrr[jss::error_message].isNull(), std::to_string(location.line()));
}
else
{
checkErrorValue(
jrr, "invalidParams", "No ledger_entry params provided.", location);
jrr,
"invalidParams",
RpcInvalidParams,
"No ledger_entry params provided.",
location);
}
}
auto const tryField = [&](json::Value fieldValue) -> void {
@@ -354,7 +372,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result];
auto const expectedErrMsg = rpc::expectedFieldMessage(
fieldName, typeNameOverride.value_or(getTypeName(typeID)));
checkErrorValue(jrr, expectedError, expectedErrMsg, location);
checkErrorValue(jrr, expectedError, RpcInvalidParams, expectedErrMsg, location);
};
auto const& badValues = getBadValues(typeID);
@@ -387,13 +405,21 @@ class LedgerEntry_test : public beast::unit_test::Suite
json::Value const jrr = env.rpc(
apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result];
checkErrorValue(
jrr, "malformedRequest", rpc::missingFieldMessage(fieldName.cStr()), location);
jrr,
"malformedRequest",
RpcInvalidParams,
rpc::missingFieldMessage(fieldName.cStr()),
location);
correctRequest[parentFieldName][fieldName] = json::ValueType::Null;
json::Value const jrr2 = env.rpc(
apiVersion, "json", "ledger_entry", to_string(correctRequest))[jss::result];
checkErrorValue(
jrr2, "malformedRequest", rpc::missingFieldMessage(fieldName.cStr()), location);
jrr2,
"malformedRequest",
RpcInvalidParams,
rpc::missingFieldMessage(fieldName.cStr()),
location);
}
auto const tryField = [&](json::Value fieldValue) -> void {
correctRequest[parentFieldName][fieldName] = fieldValue;
@@ -403,6 +429,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr,
expectedError,
RpcInvalidParams,
rpc::expectedFieldMessage(fieldName, getTypeName(typeID)),
location);
};
@@ -497,7 +524,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AA";
auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "lgrNotFound", "ledgerNotFound");
checkErrorValue(jrr, "lgrNotFound", RpcLgrNotFound, "ledgerNotFound");
}
{
// Missing ledger_entry ledger_hash
@@ -511,7 +538,10 @@ class LedgerEntry_test : public beast::unit_test::Suite
json::Value const jrr = env.rpc(
apiVersion, "json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(
jrr, "invalidParams", "Invalid field 'ledger_hash', not hex string.");
jrr,
"invalidParams",
RpcInvalidParams,
"Invalid field 'ledger_hash', not hex string.");
};
auto const& badValues = getBadValues(typeId);
@@ -530,7 +560,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
"00000000000000000000000000000000000000000000000000000000000000"
"00";
auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
forAllApiVersions([&, this](unsigned apiVersion) {
@@ -546,11 +576,15 @@ class LedgerEntry_test : public beast::unit_test::Suite
if (apiVersion < 2u)
{
checkErrorValue(jrr, "unknownOption", "");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error] == "unknownOption");
BEAST_EXPECT(!jrr.isMember(jss::error_code));
BEAST_EXPECT(jrr[jss::error_message].isNull());
}
else
{
checkErrorValue(jrr, "invalidParams", "No ledger_entry params provided.");
checkErrorValue(
jrr, "invalidParams", RpcInvalidParams, "No ledger_entry params provided.");
}
}
});
@@ -655,7 +689,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
}
@@ -854,7 +888,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Request an index that is not a check. We'll use alice's
@@ -872,7 +906,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "unexpectedLedgerType", "Unexpected ledger type.");
checkErrorValue(
jrr, "unexpectedLedgerType", RpcUnexpectedLedgerType, "Unexpected ledger type.");
}
{
// Check malformed cases
@@ -931,7 +966,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
env,
"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B"
"E4");
checkErrorValue(jv[jss::result], "entryNotFound", "Entry not found.");
checkErrorValue(jv[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
@@ -1126,7 +1161,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
auto const expectedErrMsg = fieldValue.isNull()
? rpc::missingFieldMessage(jss::issuer.cStr())
: rpc::expectedFieldMessage(jss::issuer, "AccountID");
checkErrorValue(jrr, "malformedAuthorizedCredentials", expectedErrMsg);
checkErrorValue(
jrr, "malformedAuthorizedCredentials", RpcInvalidParams, expectedErrMsg);
};
auto const& badValues = getBadValues(FieldType::AccountField);
@@ -1155,6 +1191,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::authorized_credentials, "array"));
}
@@ -1177,7 +1214,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
auto const expectedErrMsg = fieldValue.isNull()
? rpc::missingFieldMessage(jss::credential_type.cStr())
: rpc::expectedFieldMessage(jss::credential_type, "hex string");
checkErrorValue(jrr, "malformedAuthorizedCredentials", expectedErrMsg);
checkErrorValue(
jrr, "malformedAuthorizedCredentials", RpcInvalidParams, expectedErrMsg);
};
auto const& badValues = getBadValues(FieldType::BlobField);
@@ -1207,6 +1245,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr[jss::result],
"malformedRequest",
RpcInvalidParams,
"Must have exactly one of `authorized` and "
"`authorized_credentials`.");
}
@@ -1239,6 +1278,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
RpcInvalidParams,
"Invalid field 'authorized_credentials', not array of objects.");
}
@@ -1257,6 +1297,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
RpcInvalidParams,
"Invalid field 'authorized_credentials', not array of objects.");
}
@@ -1271,6 +1312,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
RpcInvalidParams,
"Invalid field 'authorized_credentials', array empty.");
}
@@ -1308,6 +1350,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr[jss::result],
"malformedAuthorizedCredentials",
RpcInvalidParams,
"Invalid field 'authorized_credentials', array too long.");
}
}
@@ -1443,7 +1486,10 @@ class LedgerEntry_test : public beast::unit_test::Suite
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(
jrr, "malformedRequest", "Must have exactly one of `owner` and `dir_root` fields.");
jrr,
"malformedRequest",
RpcInvalidParams,
"Must have exactly one of `owner` and `dir_root` fields.");
}
{
// Incomplete directory object. Missing both dir_root and owner.
@@ -1454,7 +1500,10 @@ class LedgerEntry_test : public beast::unit_test::Suite
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(
jrr, "malformedRequest", "Must have exactly one of `owner` and `dir_root` fields.");
jrr,
"malformedRequest",
RpcInvalidParams,
"Must have exactly one of `owner` and `dir_root` fields.");
}
}
@@ -1617,7 +1666,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::nft_offer][jss::seq] = offerSeq + 1000;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
// negative tests
@@ -1835,7 +1884,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Request an index that is not a payment channel.
@@ -1844,7 +1893,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
@@ -1919,6 +1968,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr,
"malformedRequest",
RpcInvalidParams,
"Invalid field 'accounts', not length-2 array of "
"Accounts.");
}
@@ -1937,6 +1987,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr,
"malformedRequest",
RpcInvalidParams,
"Invalid field 'accounts', not length-2 array of "
"Accounts.");
}
@@ -1957,6 +2008,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr,
"malformedAddress",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::accounts, "array of Accounts"));
}
@@ -1972,6 +2024,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
checkErrorValue(
jrr,
"malformedAddress",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::accounts, "array of Accounts"));
}
};
@@ -1994,7 +2047,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "Cannot have a trustline to self.");
checkErrorValue(
jrr, "malformedRequest", RpcInvalidParams, "Cannot have a trustline to self.");
}
}
}
@@ -2048,7 +2102,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Request an index that is not a signer list.
@@ -2057,7 +2111,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
@@ -2148,7 +2202,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// First real ticket requested by index.
@@ -2184,7 +2238,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Request a ticket using an account root entry.
@@ -2193,7 +2247,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "unexpectedLedgerType", "Unexpected ledger type.");
checkErrorValue(
jrr, "unexpectedLedgerType", RpcUnexpectedLedgerType, "Unexpected ledger type.");
}
{
@@ -2261,7 +2316,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::transaction_proposal][jss::ticket_seq] = ticketSeq + 1;
jvParams[jss::ledger_hash] = ledgerHash;
auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Lookup by an index of the wrong entry type.
@@ -2269,7 +2324,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::transaction_proposal] = to_string(keylet::account(target).key);
jvParams[jss::ledger_hash] = ledgerHash;
auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "unexpectedLedgerType", "Unexpected ledger type.");
checkErrorValue(
jrr, "unexpectedLedgerType", RpcUnexpectedLedgerType, "Unexpected ledger type.");
}
{
@@ -2333,7 +2389,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Malformed DID index
@@ -2455,7 +2511,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Request the MPToken using its owner + mptIssuanceID.
@@ -2478,7 +2534,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
jvParams[jss::ledger_hash] = ledgerHash;
json::Value const jrr =
env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// Malformed MPTIssuance index
@@ -2546,7 +2602,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
"12F1F1F1F180D67377B2FAB292A31C922470326268D2B9B74CD1E582645B9A"
"DE";
auto const jrr = env.rpc("json", "ledger_entry", to_string(params));
checkErrorValue(jrr[jss::result], "entryNotFound", "Entry not found.");
checkErrorValue(
jrr[jss::result], "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// test basic malformed scenarios
@@ -2592,7 +2649,9 @@ class LedgerEntry_test : public beast::unit_test::Suite
auto checkResult = [&](bool good,
json::Value const& jv,
json::StaticString const& expectedType,
std::optional<std::string> const& expectedError = {}) {
std::optional<std::string> const& expectedError = {},
ErrorCodeI expectedCode = RpcEntryNotFound,
std::string const& expectedMessage = "Entry not found.") {
if (good)
{
BEAST_EXPECTS(
@@ -2607,9 +2666,10 @@ class LedgerEntry_test : public beast::unit_test::Suite
{
BEAST_EXPECTS(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
!jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::error] == expectedError.value_or("entryNotFound"),
jv[jss::result][jss::error] == expectedError.value_or("entryNotFound") &&
jv[jss::result][jss::error_code] == expectedCode &&
jv[jss::result][jss::error_message] == expectedMessage,
to_string(jv));
}
};
@@ -2640,7 +2700,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[field] = json::ValueType::Null;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
checkResult(
false,
jv,
expectedType,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(field, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2650,7 +2716,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[field] = "arbitrary string";
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
checkResult(
false,
jv,
expectedType,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(field, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2660,7 +2732,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[field] = false;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "invalidParams");
checkResult(
false,
jv,
expectedType,
"invalidParams",
RpcInvalidParams,
rpc::expectedFieldMessage(field, "true"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2672,7 +2750,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[field] = badKey;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "entryNotFound");
checkResult(
false, jv, expectedType, "entryNotFound", RpcEntryNotFound, "Entry not found.");
BEAST_EXPECTS(jv[jss::result][jss::index] == badKey, to_string(jv));
}
@@ -2683,7 +2762,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::index] = field;
params[jss::api_version] = 2;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
checkResult(
false,
jv,
expectedType,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::index, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2722,7 +2807,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::index] = field;
params[jss::api_version] = 2;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, expectedType, "malformedRequest");
checkResult(
false,
jv,
expectedType,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::index, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2787,7 +2878,9 @@ class LedgerEntry_test : public beast::unit_test::Suite
auto checkResult = [&](bool good,
json::Value const& jv,
int expectedCount,
std::optional<std::string> const& expectedError = {}) {
std::optional<std::string> const& expectedError = {},
ErrorCodeI expectedCode = RpcEntryNotFound,
std::string const& expectedMessage = "Entry not found.") {
if (good)
{
BEAST_EXPECTS(
@@ -2807,9 +2900,10 @@ class LedgerEntry_test : public beast::unit_test::Suite
{
BEAST_EXPECTS(
jv.isObject() && jv.isMember(jss::result) &&
jv[jss::result].isMember(jss::error) &&
!jv[jss::result].isMember(jss::node) &&
jv[jss::result][jss::error] == expectedError.value_or("entryNotFound"),
jv[jss::result][jss::error] == expectedError.value_or("entryNotFound") &&
jv[jss::result][jss::error_code] == expectedCode &&
jv[jss::result][jss::error_message] == expectedMessage,
to_string(jv));
}
};
@@ -2839,7 +2933,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = json::ValueType::Null;
auto jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "malformedRequest");
checkResult(
false,
jv,
0,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::hashes, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2849,7 +2949,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = "arbitrary string";
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "malformedRequest");
checkResult(
false,
jv,
0,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::hashes, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2859,7 +2965,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = "10";
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "malformedRequest");
checkResult(
false,
jv,
0,
"malformedRequest",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::hashes, "hex string"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2869,7 +2981,13 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = false;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "invalidParams");
checkResult(
false,
jv,
0,
"invalidParams",
RpcInvalidParams,
rpc::expectedFieldMessage(jss::hashes, "true"));
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2879,7 +2997,7 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = -1;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "internal");
checkResult(false, jv, 0, "internal", RpcInternal, "Internal error.");
BEAST_EXPECT(!jv[jss::result].isMember(jss::index));
}
@@ -2890,7 +3008,8 @@ class LedgerEntry_test : public beast::unit_test::Suite
params[jss::ledger_index] = jss::validated;
params[jss::hashes] = badKey;
auto const jv = env.rpc("json", "ledger_entry", to_string(params));
checkResult(false, jv, 0, "entryNotFound");
checkResult(
false, jv, 0, "entryNotFound", RpcEntryNotFound, "Entry not found.");
BEAST_EXPECT(jv[jss::result][jss::index] == badKey);
}
@@ -3028,12 +3147,18 @@ class LedgerEntry_XChain_test : public beast::unit_test::Suite,
public test::jtx::XChainBridgeObjects
{
void
checkErrorValue(json::Value const& jv, std::string const& err, std::string const& msg)
checkErrorValue(
json::Value const& jv,
std::string const& err,
ErrorCodeI code,
std::string const& msg)
{
if (BEAST_EXPECT(jv.isMember(jss::status)))
BEAST_EXPECT(jv[jss::status] == "error");
if (BEAST_EXPECT(jv.isMember(jss::error)))
BEAST_EXPECT(jv[jss::error] == err);
if (BEAST_EXPECT(jv.isMember(jss::error_code)))
BEAST_EXPECT(jv[jss::error_code] == code);
if (msg.empty())
{
BEAST_EXPECT(
@@ -3110,7 +3235,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::Suite,
json::Value const jrr =
mcEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
{
// create two claim ids and verify that the bridge counter was
@@ -3297,7 +3422,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::Suite,
[jss::xchain_owned_create_account_claim_id] = 1;
json::Value const jrr =
scEnv.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "Entry not found.");
checkErrorValue(jrr, "entryNotFound", RpcEntryNotFound, "Entry not found.");
}
}
Loaded 100 of 130 files, more files were not shown because too many files have changed in this diff. Show more