Skip to content

An amount above 2^53 is not the amount that was given - #5

Open
tempoloss wants to merge 1 commit into
GoPlasmatic:mainfrom
tempoloss:test/amount-above-2-53-is-rounded
Open

An amount above 2^53 is not the amount that was given#5
tempoloss wants to merge 1 commit into
GoPlasmatic:mainfrom
tempoloss:test/amount-above-2-53-is-rounded

Conversation

@tempoloss

Copy link
Copy Markdown

An amount above 2^53 is not the amount that was given

ActiveOrHistoricCurrencyAndAmount.value is f64 (src/document/camt_053_001_08.rs:342),
and so is AmountAndDirection35.amt (:691). f64 holds integers exactly up to
2^53, which is 9007199254740992. Above that the parsed amount is a different
number than the one on the wire, and the crate reports success either way.

tests/amount_precision.rs parses one amount and fails:

cargo test --test amount_precision

assertion `left == right` failed
  left: "123456789012345680"
 right: "123456789012345678"

The pipeline cannot see this. I put the same amount into a copy of
simplified_statement.json and ran it: Generate, Publish, Validate, Parse all
report 1/1 and the round-trip matches, while the published XML reads
<Amt Ccy="USD">123456789012345680</Amt>. Both sides of the comparison are
already f64, so a rounded amount matches itself. The seven camt053 scenarios
carry 5000.0, 10000.0, 11500.0, 25000.0, 50000.0, 100000.0, 500000.0 and
750000.0, every one of which f64 represents exactly, so the corpus has never
put the type under pressure.

Two things this is not:

  • Not a problem for a normal CBPR+ payment. Below 2^53 the text round-trips
    exactly, because Rust prints the shortest representation that parses back.
    It starts to matter for aggregate balances in VND or IDR, where a
    country-scale figure passes 9.0e15 on its own.
  • Not something I can size against your schemas. xsd/ is gitignored, so the
    18 significant digits I am testing against come from the base ISO 20022
    amount type, not from your CBPR+ SR2025 restriction. If SR2025 caps
    totalDigits lower than 18, say so and this is a non-issue.

The fix does not belong in src/document/. generate.sh opens with
rm -rf src/document/, so a patched struct is gone at the next generation. The
mapping is upstream in xuri/xgen, utils.go, BuildInTypes, where the fifth
column is Rust:

	"decimal":            {"float64", "number", "float", "Float", "f64"},

The place that survives regeneration is the post-processing this repo already
runs, apply-box-wrapping.py with box-config.json. A decimal string is what
the other generated models use: rust_iso20022 keeps every scalar as String
and gives the reason in its README, lossless exact text with no float rounding.

This PR is the test only. It fails today.


Dropped before opening this: a second test asserting that BkToCstmrStmt/Stmt
should be Vec. It should not, for this crate. AccountStatement91 in the same
struct has bal: Vec<CashBalance81> and ntry: Option<Vec<Box<ReportEntry101>>>,
so xgen does emit a sequence when the schema says unbounded, which means the
singular stmt came from CBPR+ restricting it to 1..1. Base ISO 20022 models
such as rust_iso20022 and open-payments-iso20022-camt use Vec there, but
they are generated from the unrestricted schemas and are not comparable.

ActiveOrHistoricCurrencyAndAmount.value is f64, which holds integers exactly
only below 2^53. 123456789012345678 parses as 123456789012345680 and nothing
reports it.

The pipeline cannot catch this: the round-trip compares parsed values, so a
rounded amount matches itself, and the seven camt053 scenarios carry round
balances f64 represents exactly. Feeding this amount through a scenario passes
all four steps while the published XML reads 123456789012345680.

Below 2^53 the text round-trips exactly, so this bites aggregate balances in
currencies like VND or IDR rather than an ordinary CBPR+ payment.
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.

1 participant