From f890e6d1d2c42a25dc9bc7e721ac8c64e781c02a Mon Sep 17 00:00:00 2001 From: Andrea Raspitzu Date: Thu, 25 Jul 2019 12:40:13 +0200 Subject: [PATCH] Support for lossless comparisons between different BtcAmount --- .../scala/fr/acinq/bitcoin/BtcAmount.scala | 91 ++++++++++++++++++- .../fr/acinq/bitcoin/BtcAmountSpec.scala | 16 ++++ 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/main/scala/fr/acinq/bitcoin/BtcAmount.scala b/src/main/scala/fr/acinq/bitcoin/BtcAmount.scala index c2bb4569..587b17d1 100644 --- a/src/main/scala/fr/acinq/bitcoin/BtcAmount.scala +++ b/src/main/scala/fr/acinq/bitcoin/BtcAmount.scala @@ -1,6 +1,11 @@ package fr.acinq.bitcoin -sealed trait BtcAmount +sealed trait BtcAmount { + def toMilliSatoshi: MilliSatoshi + def toSatoshi: Satoshi = millisatoshi2satoshi(toMilliSatoshi) + def toMilliBtc: MilliBtc = satoshi2millibtc(toSatoshi) + def toBtc: Btc = millibtc2btc(toMilliBtc) +} case class Satoshi(amount: Long) extends BtcAmount { // @formatter:off @@ -9,12 +14,31 @@ case class Satoshi(amount: Long) extends BtcAmount { def -(other: Satoshi) = Satoshi(amount - other.amount) def *(m: Long) = Satoshi(amount * m) def /(d: Long) = Satoshi(amount / d) - def compare(other: Satoshi): Int = if (amount == other.amount) 0 else if (amount < other.amount) -1 else 1 + + def compare(other: BtcAmount): Int = this.toMilliSatoshi.compare(other.toMilliSatoshi) + + def <= (that: MilliSatoshi): Boolean = compare(that) <= 0 def <= (that: Satoshi): Boolean = compare(that) <= 0 + def <= (that: MilliBtc): Boolean = compare(that) <= 0 + def <= (that: Btc): Boolean = compare(that) <= 0 + + def >= (that: MilliSatoshi): Boolean = compare(that) >= 0 def >= (that: Satoshi): Boolean = compare(that) >= 0 + def >= (that: MilliBtc): Boolean = compare(that) >= 0 + def >= (that: Btc): Boolean = compare(that) >= 0 + + def < (that: MilliSatoshi): Boolean = compare(that) < 0 def < (that: Satoshi): Boolean = compare(that) < 0 + def < (that: MilliBtc): Boolean = compare(that) < 0 + def < (that: Btc): Boolean = compare(that) < 0 + + def > (that: MilliSatoshi): Boolean = compare(that) > 0 def > (that: Satoshi): Boolean = compare(that) > 0 + def > (that: MilliBtc): Boolean = compare(that) > 0 + def > (that: Btc): Boolean = compare(that) > 0 + def unary_-() = Satoshi(-amount) + def toMilliSatoshi: MilliSatoshi = satoshi2millisatoshi(this) // @formatter:on } @@ -24,12 +48,31 @@ case class MilliBtc(amount: BigDecimal) extends BtcAmount { def -(other: MilliBtc) = MilliBtc(amount - other.amount) def *(m: Long) = MilliBtc(amount * m) def /(d: Long) = MilliBtc(amount / d) - def compare(other: MilliBtc): Int = if (amount == other.amount) 0 else if (amount < other.amount) -1 else 1 + + def compare(other: BtcAmount): Int = this.toMilliSatoshi.compare(other.toMilliSatoshi) + + def <= (that: MilliSatoshi): Boolean = compare(that) <= 0 + def <= (that: Satoshi): Boolean = compare(that) <= 0 def <= (that: MilliBtc): Boolean = compare(that) <= 0 + def <= (that: Btc): Boolean = compare(that) <= 0 + + def >= (that: MilliSatoshi): Boolean = compare(that) >= 0 + def >= (that: Satoshi): Boolean = compare(that) >= 0 def >= (that: MilliBtc): Boolean = compare(that) >= 0 + def >= (that: Btc): Boolean = compare(that) >= 0 + + def < (that: MilliSatoshi): Boolean = compare(that) < 0 + def < (that: Satoshi): Boolean = compare(that) < 0 def < (that: MilliBtc): Boolean = compare(that) < 0 + def < (that: Btc): Boolean = compare(that) < 0 + + def > (that: MilliSatoshi): Boolean = compare(that) > 0 + def > (that: Satoshi): Boolean = compare(that) > 0 def > (that: MilliBtc): Boolean = compare(that) > 0 + def > (that: Btc): Boolean = compare(that) > 0 + def unary_-() = MilliBtc(-amount) + def toMilliSatoshi: MilliSatoshi = millibtc2millisatoshi(this) // @formatter:on } @@ -41,12 +84,31 @@ case class Btc(amount: BigDecimal) extends BtcAmount { def -(other: Btc) = Btc(amount - other.amount) def *(m: Long) = Btc(amount * m) def /(d: Long) = Btc(amount / d) - def compare(other: Btc): Int = if (amount == other.amount) 0 else if (amount < other.amount) -1 else 1 + + def compare(other: BtcAmount): Int = this.toMilliSatoshi.compare(other.toMilliSatoshi) + + def <= (that: MilliSatoshi): Boolean = compare(that) <= 0 + def <= (that: Satoshi): Boolean = compare(that) <= 0 + def <= (that: MilliBtc): Boolean = compare(that) <= 0 def <= (that: Btc): Boolean = compare(that) <= 0 + + def >= (that: MilliSatoshi): Boolean = compare(that) >= 0 + def >= (that: Satoshi): Boolean = compare(that) >= 0 + def >= (that: MilliBtc): Boolean = compare(that) >= 0 def >= (that: Btc): Boolean = compare(that) >= 0 + + def < (that: MilliSatoshi): Boolean = compare(that) < 0 + def < (that: Satoshi): Boolean = compare(that) < 0 + def < (that: MilliBtc): Boolean = compare(that) < 0 def < (that: Btc): Boolean = compare(that) < 0 + + def > (that: MilliSatoshi): Boolean = compare(that) > 0 + def > (that: Satoshi): Boolean = compare(that) > 0 + def > (that: MilliBtc): Boolean = compare(that) > 0 def > (that: Btc): Boolean = compare(that) > 0 + def unary_-() = Btc(-amount) + def toMilliSatoshi: MilliSatoshi = btc2millisatoshi(this) // @formatter:on } @@ -57,12 +119,31 @@ case class MilliSatoshi(amount: Long) extends BtcAmount { def -(other: MilliSatoshi) = MilliSatoshi(amount - other.amount) def *(m: Long) = MilliSatoshi(amount * m) def /(d: Long) = MilliSatoshi(amount / d) - def compare(other: MilliSatoshi): Int = if (amount == other.amount) 0 else if (amount < other.amount) -1 else 1 + + def compare(other: BtcAmount): Int = if (amount == other.toMilliSatoshi.amount) 0 else if (amount < other.toMilliSatoshi.amount) -1 else 1 + def <= (that: MilliSatoshi): Boolean = compare(that) <= 0 + def <= (that: Satoshi): Boolean = compare(that) <= 0 + def <= (that: MilliBtc): Boolean = compare(that) <= 0 + def <= (that: Btc): Boolean = compare(that) <= 0 + def >= (that: MilliSatoshi): Boolean = compare(that) >= 0 + def >= (that: Satoshi): Boolean = compare(that) >= 0 + def >= (that: MilliBtc): Boolean = compare(that) >= 0 + def >= (that: Btc): Boolean = compare(that) >= 0 + def < (that: MilliSatoshi): Boolean = compare(that) < 0 + def < (that: Satoshi): Boolean = compare(that) < 0 + def < (that: MilliBtc): Boolean = compare(that) < 0 + def < (that: Btc): Boolean = compare(that) < 0 + def > (that: MilliSatoshi): Boolean = compare(that) > 0 + def > (that: Satoshi): Boolean = compare(that) > 0 + def > (that: MilliBtc): Boolean = compare(that) > 0 + def > (that: Btc): Boolean = compare(that) > 0 + def unary_-() = MilliSatoshi(-amount) + def toMilliSatoshi: MilliSatoshi = this // @formatter:on } diff --git a/src/test/scala/fr/acinq/bitcoin/BtcAmountSpec.scala b/src/test/scala/fr/acinq/bitcoin/BtcAmountSpec.scala index 1ed19c10..34621e74 100644 --- a/src/test/scala/fr/acinq/bitcoin/BtcAmountSpec.scala +++ b/src/test/scala/fr/acinq/bitcoin/BtcAmountSpec.scala @@ -66,6 +66,22 @@ class BtcAmountSpec extends FunSuite { assert(MilliSatoshi(32) > MilliSatoshi(31)) } + test("lossless comparisons") { + assert(Satoshi(2) < MilliSatoshi(2999)) + assert(Satoshi(3) > MilliSatoshi(2999)) + assert(!(Satoshi(2) >= MilliSatoshi(2999))) + assert(!(Satoshi(3) < MilliSatoshi(2999))) + assert(MilliSatoshi(2999) >= Satoshi(2)) + assert(!(MilliSatoshi(2999) < Satoshi(2))) + assert(MilliSatoshi(2001).toBtc >= Satoshi(2).toBtc) + assert(!(MilliSatoshi(2001).toBtc < Satoshi(2).toBtc)) + assert(Satoshi(2000001).compare(MilliSatoshi(2000001000)) == 0) + assert(Satoshi(2000001) > MilliSatoshi(2000000001)) + assert(MilliBtc(20) < Satoshi(2000001)) + assert(MilliBtc(20) < MilliSatoshi(2000000001)) + assert(Satoshi(2000001) > MilliBtc(20)) + } + test("negate amount") { assert(Satoshi(-20) == -Satoshi(20)) }