Skip to content

perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast#7402

Open
Tapanito wants to merge 2 commits into
developfrom
tapanito/perf-stamount
Open

perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast#7402
Tapanito wants to merge 2 commits into
developfrom
tapanito/perf-stamount

Conversation

@Tapanito
Copy link
Copy Markdown
Collaborator

@Tapanito Tapanito commented Jun 4, 2026

High Level Overview of Change

hasInvalidAmount runs on the per-transaction invariant-checking path (ValidAmounts::finalize) and at preflight (Transactor::preflightUniversal), recursively walking every field of every modified ledger entry / transaction.

The previous implementation tried a dynamic_cast chain (STAmount, then STObject, then STArray) on each field. Every scalar non-amount field — the common case in real entries — paid up to three failed RTTI casts before falling through.

This change dispatches on the serialized type tag via getSType() and a switch. The object-like tags all denote STObject subclasses (STLedgerEntry, STTx), so the downcast is sound; safeDowncast keeps a dynamic_cast validity assert in debug builds while compiling to static_cast in release.

Type of Change

  • Performance (increases or improves the performance of the code, without changing existing behavior)

Benchmark

A micro-benchmark over a representative entry (a mix of scalar fields plus a nested array of sub-objects), running both implementations in one Release binary on identical data:

dynamic_cast chain (old): 941.595 ns/call (1883 ms total)
getSType switch  (new): 73.1029 ns/call (146 ms total)

~12.9× faster. The win scales with the number of non-amount fields, since those are exactly the fields that previously incurred the full failed-cast chain. Behavior is unchanged — both implementations return identical results across the test inputs.

🤖 Generated with Claude Code

hasInvalidAmount runs on the per-transaction invariant-checking path
(ValidAmounts::finalize) and at preflight, walking every field of every
modified entry. The previous implementation tried a dynamic_cast chain
(STAmount, STObject, STArray) on each field, so every scalar non-amount
field paid three failed RTTI casts.

Dispatch on the serialized type tag via getSType() and a switch instead.
The object-like tags all denote STObject subclasses (STLedgerEntry, STTx),
so the downcast is sound; safeDowncast keeps a dynamic_cast validity
assert in debug builds while compiling to static_cast in release.
@Tapanito Tapanito requested review from bthomee and gregtatcam June 4, 2026 13:28
Copy link
Copy Markdown
Contributor

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Choose a reason for hiding this comment

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

No issues.

Review by Claude Sonnet 4.6 · Prompt: V15

Copy link
Copy Markdown
Collaborator

@gregtatcam gregtatcam left a comment

Choose a reason for hiding this comment

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

👍 LGTM

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.4%. Comparing base (6571f75) to head (f2b226f).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           develop   #7402   +/-   ##
=======================================
  Coverage     82.3%   82.4%           
=======================================
  Files         1011    1011           
  Lines        76913   76916    +3     
  Branches      8965    8965           
=======================================
+ Hits         63335   63342    +7     
+ Misses       13569   13565    -4     
  Partials         9       9           
Files with missing lines Coverage Δ
src/libxrpl/protocol/STAmount.cpp 88.7% <100.0%> (+<0.1%) ⬆️

... and 4 files with indirect coverage changes

Impacted file tree graph

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ximinez ximinez changed the title perf: Dispatch hasInvalidAmount on type tag instead of dynamic_cast perf: Dispatch "hasInvalidAmount" on type tag instead of dynamic_cast Jun 5, 2026
@ximinez ximinez changed the title perf: Dispatch "hasInvalidAmount" on type tag instead of dynamic_cast perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast Jun 5, 2026
Copy link
Copy Markdown
Collaborator

@ximinez ximinez left a comment

Choose a reason for hiding this comment

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

This looks good. I have one question / suggestion, but I'll approve either way.

Also, I changed the title of the PR because I kept reading "hasInvalidAmount" as three words instead of a function name, then edited for length.

Comment thread src/libxrpl/protocol/STAmount.cpp
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes hasInvalidAmount() (used during invariant checking and preflight validation) by replacing a per-field dynamic_cast chain with dispatch on STBase::getSType() via a switch, reducing repeated failed RTTI casts for the common non-amount scalar-field case.

Changes:

  • Replaced dynamic_cast-based type probing with getSType() + switch dispatch in hasInvalidAmount(STBase const&, ...).
  • Introduced safeDowncast-based downcasts for amount/object/array cases to keep debug-time validation while using static_cast in release.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@xrplf-ai-reviewer xrplf-ai-reviewer Bot left a comment

Choose a reason for hiding this comment

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

No issues.

Review by Claude Sonnet 4.6 · Prompt: V15

@Tapanito Tapanito requested a review from ximinez June 5, 2026 18:36
@bthomee bthomee added this to the 3.2.0 milestone Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants