Adding 'Bitconis' Currency unit type, adding unary '-' operator to negate the underlying values of CurrencyUnits / Int32s / Int64s

This commit is contained in:
Chris Stewart 2017-05-02 12:01:44 -05:00
parent 2ca4627ca7
commit 1bf3558cf5
4 changed files with 70 additions and 17 deletions

View file

@ -1,5 +1,6 @@
package org.bitcoins.core.currency
import org.bitcoins.core.consensus.Consensus
import org.bitcoins.core.number.{BaseNumbers, Int32, Int64, SignedNumber}
import org.bitcoins.core.protocol.NetworkElement
import org.bitcoins.core.serializers.{RawBitcoinSerializerHelper, RawSatoshisSerializer}
@ -10,41 +11,48 @@ sealed trait CurrencyUnit extends NetworkElement with BitcoinSLogger {
type A
def underlying : A
def satoshis: Satoshis
def >=(c : CurrencyUnit) : Boolean = {
CurrencyUnits.toSatoshis(this).underlying >= CurrencyUnits.toSatoshis(c).underlying
satoshis.underlying >= c.satoshis.underlying
}
def >(c : CurrencyUnit) : Boolean = {
CurrencyUnits.toSatoshis(this).underlying > CurrencyUnits.toSatoshis(c).underlying
satoshis.underlying > c.satoshis.underlying
}
def <(c : CurrencyUnit) : Boolean = {
CurrencyUnits.toSatoshis(this).underlying < CurrencyUnits.toSatoshis(c).underlying
satoshis.underlying < c.satoshis.underlying
}
def <=(c : CurrencyUnit) : Boolean = {
CurrencyUnits.toSatoshis(this).underlying <= CurrencyUnits.toSatoshis(c).underlying
satoshis.underlying <= c.satoshis.underlying
}
def !=(c : CurrencyUnit) : Boolean = !(this == c)
def +(c : CurrencyUnit) : CurrencyUnit = {
Satoshis(CurrencyUnits.toSatoshis(this).underlying + CurrencyUnits.toSatoshis(c).underlying)
Satoshis(satoshis.underlying + c.satoshis.underlying)
}
def -(c : CurrencyUnit) : CurrencyUnit = {
Satoshis(CurrencyUnits.toSatoshis(this).underlying - CurrencyUnits.toSatoshis(c).underlying)
Satoshis(satoshis.underlying - c.satoshis.underlying)
}
def *(c : CurrencyUnit) : CurrencyUnit = {
Satoshis(CurrencyUnits.toSatoshis(this).underlying * CurrencyUnits.toSatoshis(c).underlying)
Satoshis(satoshis.underlying * c.satoshis.underlying)
}
def unary_- : CurrencyUnit = {
Satoshis(- satoshis.underlying)
}
}
sealed trait Satoshis extends CurrencyUnit {
override type A = Int64
override def hex = RawSatoshisSerializer.write(this)
override def satoshis: Satoshis = this
}
object Satoshis extends Factory[Satoshis] with BaseNumbers[Satoshis] {
@ -60,14 +68,41 @@ object Satoshis extends Factory[Satoshis] with BaseNumbers[Satoshis] {
def apply(int64: Int64): Satoshis = SatoshisImpl(int64)
}
object CurrencyUnits {
def zero : CurrencyUnit = Satoshis.zero
def negativeSatoshi = Satoshis(Int64(-1))
/** The number you need to multiply BTC by to get it's satoshis */
def btcToSatoshiScalar = 100000000
sealed trait Bitcoins extends CurrencyUnit {
override type A = BigDecimal
override def satoshis: Satoshis = {
val sat = underlying * CurrencyUnits.btcToSatoshiScalar
Satoshis(Int64(sat.toLongExact))
}
override def hex = satoshis.hex
}
def oneBTC: CurrencyUnit = Satoshis(Int64(btcToSatoshiScalar))
def toSatoshis(unit : CurrencyUnit): Satoshis = unit match {
case x : Satoshis => x
object Bitcoins extends BaseNumbers[Bitcoins] {
val min = Bitcoins((-Consensus.maxMoney).satoshis)
val max = Bitcoins(Consensus.maxMoney.satoshis)
val zero = Bitcoins(Satoshis.zero)
val one = Bitcoins(1)
private case class BitcoinsImpl(underlying: BigDecimal) extends Bitcoins
def apply(underlying: BigDecimal): Bitcoins = BitcoinsImpl(underlying)
def apply(satoshis: Satoshis): Bitcoins = {
val b = satoshis.underlying.underlying * CurrencyUnits.satoshisToBTCScalar
BitcoinsImpl(b)
}
}
object CurrencyUnits {
def zero: CurrencyUnit = Satoshis.zero
def negativeSatoshi = Satoshis(Int64(-1))
/** The number you need to multiply BTC by to get it's satoshis */
def btcToSatoshiScalar: Long = 100000000
def satoshisToBTCScalar: BigDecimal = BigDecimal(1.0) / btcToSatoshiScalar
def oneBTC: CurrencyUnit = Satoshis(Int64(btcToSatoshiScalar))
def toSatoshis(unit : CurrencyUnit): Satoshis = unit match {
case b: Bitcoins => b.satoshis
case x: Satoshis => x
}
}

View file

@ -82,6 +82,8 @@ sealed trait UInt32 extends UnsignedNumber with NumberOperations[UInt32] {
def & (num : UInt32) : UInt32 = UInt32(underlying & num.underlying)
override def hex = BitcoinSUtil.encodeHex(underlying).slice(8,16)
override def toInt = {
@ -207,6 +209,7 @@ sealed trait Int32 extends SignedNumber with NumberOperations[Int32] {
override def <= (num : Int32): Boolean = underlying <= num.underlying
def unary_- : Int32 = Int32(-underlying)
def | (num : Int32) : Int32 = Int32(underlying | num.underlying)
def & (num : Int32) : Int32 = Int32(underlying & num.underlying)
@ -261,6 +264,8 @@ sealed trait Int64 extends SignedNumber with NumberOperations[Int64] {
override def <= (num : Int64): Boolean = underlying <= num.underlying
def unary_- : Int64 = Int64(-underlying)
def | (num : Int64) : Int64 = Int64(underlying | num.underlying)
def & (num : Int64) : Int64 = Int64(underlying & num.underlying)

View file

@ -1,6 +1,7 @@
package org.bitcoins.core.number
import org.bitcoins.core.gen.NumberGenerator
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{Prop, Properties}
import scala.util.Try
@ -8,8 +9,7 @@ import scala.util.Try
/**
* Created by chris on 6/21/16.
*/
class Int32Spec extends Properties("Int32Spec") {
class Int32Spec extends Properties("Int32Spec") with BitcoinSLogger {
property("Serialization symmetry") =
Prop.forAll(NumberGenerator.int32s) { int32: Int32 =>
@ -86,4 +86,10 @@ class Int32Spec extends Properties("Int32Spec") {
Prop.forAll(NumberGenerator.int32s, NumberGenerator.int32s) { (num1: Int32, num2: Int32) =>
Int32(num1.underlying & num2.underlying) == (num1 & num2)
}
property("negation") = {
Prop.forAll(NumberGenerator.int32s) { int32 =>
-int32 == Int32(-int32.underlying)
}
}
}

View file

@ -86,5 +86,12 @@ class Int64Spec extends Properties("Int64Spec") {
Prop.forAll(NumberGenerator.int64s, NumberGenerator.int64s) { (num1: Int64, num2: Int64) =>
Int64(num1.underlying & num2.underlying) == (num1 & num2)
}
property("negation") = {
Prop.forAll(NumberGenerator.int64s) { int64 =>
-int64 == Int64(-int64.underlying)
}
}
}