Skip to content

Thoughts on the interaction of STAmount and STNumber with expanded mantissas (an offshoot of #6025) #6105

@ximinez

Description

@ximinez

Description

Before Lending Protocol (#5270) was merged in to develop, I considered DRAFT: Expand Number to support the full integer range #6025 to be more-or-less done.

Integrating the two together has been more "interesting" than I expected. There have been a few hard-coded test case values that need to be updated, but those aren't a big deal.

The challenge has come in one particular check:

ripple.tx.Loan Lifecycle: 1000 IOU Scale interest to: 0 Loan overpayment allowed - Impair and Default
#233 failed: Loan_test.cpp(312)

The test on line 312 is:

                    env.test.BEAST_EXPECT(
                        vaultSle->at(sfAssetsAvailable) ==
                        env.balance(vaultPseudo, broker.asset).number());

This is checking that "Assets Available" in the Vault is the same as the actual balance of the Vault pseudo-account for that asset. In this case, the values are:

  • Assets Available, which is an STNumber: 999025.0003706351120
  • Pseudo-account balance, which is an STAmount: 999025.0003706351000

The values are identical to 16 digits of precision. STAmount is designed to have 16 digits of precision for IOU values. STNumber, however, has been expanded to 19 digits of precision for all values as part of #6025.

tl;dr

STNumber is too precise to represent IOU values.

Solutions

I can think of two general solutions to this problem:

Solution 1: Expand STAmount, too

Basically apply the same STNumber expansion to STAmount.

There are several reasons not to do this, the biggest of which is UGH.

Also:

  1. STAmount is far more pervasive across the system. Messing with it has a much higher level of risk than messing with STNumber.
  2. The serialization format for STAmount uses some of the bits of the 64-bit mantissa to encode extra information for XRP and IOU values. Storing the entire 64-bit number would require redesigning the serialization at least for those types. This is a very complex and risky task, which would also require backward-compatibility for existing ledger values. (There are no STNumbers on ledger.)
  3. The serialized STAmount would also be bigger, requiring more resources across the entire network. There are a lot of STNumbers STAmounts on the mainnet ledger.

Solution 2: A bit of a redesign

I propose these changes to the design of the Vault, LoanBroker, and Loan objects and transactions.

  1. I mentioned above that Assets Available is supposed to match the pseudo-account balance. If they're required to always stay in sync, then one is redundant. Because balances are needed system-wide, get rid of sfAssetsAvailable.
    • As far as I can tell, it serves no functional purpose, except maybe the convenience of skipping a lookup to get the pseudo-account balance.
    • Most transactions that are going to be interacting with sfAssetsAvailable are going to be using the real balance in some way anyway, and loading the balance for those that don't is only going to require loading one more object, a relatively small cost.
    • The field will no longer be available to RPC queries, but any such queries where it might be relevant could return the balance as a composite field.
  2. Conceptually, an STAmount is an STNumber combined with an STIssue. The Vault object has the sfAsset field, which is an STIssue, and the sfAssetsTotal field, which is an STNumber. Combine STIssue sfAsset with STNumber sfAssetsTotal into a single STAmount sfAssetsTotal field in the Vault object.
    • This will give us the desired rounding automatically.
    • Accessing a Vault's asset type would be a simple change from sle[sfAssets] to sle[sfAssetsTotal].asset().
    • There would be no undesired side effects from changing sfAssetsTotal because it is only defined in the Vault object, no transaction layouts, and only referenced by Vault and Loan transactors - which are still behind amendment gates.
  3. That leaves about 15 STNumber fields, all of which are only used by Vault, LoanBrokers, and Loans. Any that are part of a Loan have already been thoroughly vetted for rounding safety and agreement with the Vault. Audit STNumber fields that represent "real" asset amounts, and convert them into and back out of an STAmount any time they are stored or altered.
    • That will force them to be rounded appropriately for IOUs, MPTs, and XRP if they aren't already so that they fit into the expected accuracy.
    • Looking at the fields list, I think the only ones that will need any attention are sfLossUnrealized, sfCoverAvailable, sfDebtTotal, and maybe sfAssetsMaximum.
    • Absolutely do not mess with sfPeriodicPayment.

Feedback

I'm putting this proposal out before implementing it so I can get feedback from interested parties. Is there anything else I should consider? Is there a use for sfAssetsAvailable that I don't know about, or a need for it to be able to differ from the pseudo-account balance? Do you have any better or simpler ideas? I'd love to hear them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions