perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast#7402
perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast#7402Tapanito wants to merge 2 commits into
Conversation
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.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ 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
🚀 New features to boost your workflow:
|
ximinez
left a comment
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 withgetSType()+switchdispatch inhasInvalidAmount(STBase const&, ...). - Introduced
safeDowncast-based downcasts for amount/object/array cases to keep debug-time validation while usingstatic_castin release.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
High Level Overview of Change
hasInvalidAmountruns 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_castchain (STAmount, thenSTObject, thenSTArray) 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 aswitch. The object-like tags all denoteSTObjectsubclasses (STLedgerEntry,STTx), so the downcast is sound;safeDowncastkeeps adynamic_castvalidity assert in debug builds while compiling tostatic_castin release.Type of Change
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:
~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