Skip to content

feat: add BigDecimal type to CVM (bounty #5)#578

Closed
aglichandrap wants to merge 1 commit into
Convex-Dev:developfrom
aglichandrap:feature/bigdecimal
Closed

feat: add BigDecimal type to CVM (bounty #5)#578
aglichandrap wants to merge 1 commit into
Convex-Dev:developfrom
aglichandrap:feature/bigdecimal

Conversation

@aglichandrap

Copy link
Copy Markdown

Summary

Implements arbitrary-precision decimal arithmetic for the CVM numeric tower, fulfilling bounty #5.

Changes

  • CVMBigDecimal.java: Wraps java.math.BigDecimal, extends ANumeric

    • Exact decimal arithmetic (add, sub, multiply, divide)
    • Type promotion: Decimal op Integer → Decimal, Decimal op Double → Double
    • CAD3 encoding: tag 0x1a + VLQ signed scale + VLQ byte count + unscaled bytes
    • Canonical if and only if value has meaningful fractional digits (integers stay as Long/BigInteger)
  • Decimal.java: Type class for CVMBigDecimal registered as Types.DECIMAL

  • Core.java: Registers bigdecimal (code 260) constructor and bigdecimal? (code 261) predicate

  • CAD3Encoder.java: Decodes tag 0x1a → reads VLQ scale, VLQ byte count, unscaled bytes → constructs CVMBigDecimal

  • Juice.java: costNumeric() charges proportional to unscaled byte length (same as BigInteger)

  • RT.java: ensureBigDecimal() conversion from any numeric type

  • Tag.java: BIG_DECIMAL = 0x1a

  • Symbols.java: BIGDECIMAL, BIGDECIMAL_Q

Design Decisions

  • Code 260 for bigdecimal constructor, 261 for bigdecimal? predicate
  • Tag 0x1a for wire format (between BIG_INTEGER=0x19 and DOUBLE=0x1D)
  • Canonicality: Only decimals with fractional digits are canonical; integers always reduce to CVMLong/CVMBigInteger
  • Division: Non-terminating decimal division throws ArithmeticException (preserves exactness)
  • Numeric dispatch: CVMBigDecimal handles Integer operands directly; falls back to Double for CVMDouble operands

Fixes #5

Implements arbitrary-precision decimal arithmetic for the CVM numeric tower.

- CVMBigDecimal.java: wraps java.math.BigDecimal, extends ANumeric
  - Exact decimal arithmetic (add, sub, multiply, divide)
  - Type promotion: Decimal op Integer -> Decimal, Decimal op Double -> Double
  - CAD3 encoding: tag 0x1a + VLQ scale + VLQ byte count + unscaled bytes
  - Canonical if and only if value has meaningful fractional digits

- Decimal.java: type class for CVMBigDecimal (Types.DECIMAL)
- Core.java: register 'bigdecimal' (code 260) constructor and 'bigdecimal?' (code 261) predicate
- CAD3Encoder.java: decode tag 0x1a for BigDecimal wire format
- Juice.java: costNumeric() handles CVMBigDecimal (proportional to unscaled byte length)
- RT.java: ensureBigDecimal() conversion utility
- Tag.java: BIG_DECIMAL = 0x1a
- Symbols.java: BIGDECIMAL, BIGDECIMAL_Q

Fixes Convex-Dev#5
@mikera

mikera commented Jul 6, 2026

Copy link
Copy Markdown
Member

(Claude Comment) Thanks @aglichandrap — putting this one formally on hold rather than into code review.

The reason is upstream of the implementation: we first need to determine whether a decimal type belongs in the CVM numeric tower at all. A new type is a permanent consensus commitment — the CAD3 tag allocation (0x1a is currently unallocated, but allocating it is forever), plus equality/hashing/promotion semantics across the tower, plus juice pricing. Those are specification decisions that belong in a CAD design discussion in the design repo, not a code PR — and the outcome may legitimately be "no" (many platforms deliberately stay with integer + IEEE double, pushing fixed-point decimal semantics to actor-level libraries).

If the design discussion concludes it makes sense, it would land via the versioned migration mechanism (v2 at the earliest, using the regNonGenesis pattern) and this PR would be a strong starting point for the implementation. Until then, please hold off investing further code effort. Appreciated — the encoding work here is careful, and the bounty remains open pending the design outcome.

@brittleboye

Copy link
Copy Markdown
Collaborator

Thank you for this — it's a substantial and carefully-built implementation, and the effort on bounty #5 is appreciated. We've decided not to take it forward, for a reason of design direction rather than code quality.

A BigDecimal type isn't a good fit for the CVM numeric tower. The design intent is two numeric kinds, each with a clear role:

  • Integers — arbitrary-precision and exact — for anything that must be precise. Exact decimal and fixed-point values are best represented as integers in the smallest unit with an explicit scale (the same way coin amounts use copper, where 1 Gold = 10^9 copper), which keeps arithmetic exact and deterministic.
  • Doubles — IEEE 754, with deterministically specified behaviour across the network — for real-valued computation.

Between them these cover the precise and the approximate cases. A third, arbitrary-precision decimal type doesn't open up a use case the existing two don't already serve, while it does add consensus-critical surface area — a new CAD3 encoding tag, new core functions, and extra promotion rules in the numeric tower — that we'd rather not carry.

There's also a timing point: this is squarely out of scope for the v1 protocol upgrade. And mechanically, a new CAD3 tag (0x1a) plus new genesis core functions would have to go through the network upgrade mechanism rather than a direct change to the encoding and core environment. But the primary reason is the design one above.

Closing on that basis — with genuine thanks for the quality of the work.

— Claude (AI assistant helping maintain the Convex repository, on behalf of the maintainers)

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.

Scrypt - if statement

3 participants