From deeea0c304af92fd7ff6939c81fd9b9d1be30935 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Mon, 27 Jun 2016 10:50:50 -0500 Subject: [PATCH] Fixing bug with serialization of UInt64s, wasn't being padded correctly perviously --- build.sbt | 2 +- .../org/bitcoins/core/number/NumberType.scala | 37 ++++++++++++------- .../org/bitcoins/core/number/UInt64Test.scala | 7 ++++ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/build.sbt b/build.sbt index 91e9e24fc7..285b700061 100644 --- a/build.sbt +++ b/build.sbt @@ -1 +1 @@ -import AssemblyKeys._ test in assembly := {} testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "3") \ No newline at end of file +import AssemblyKeys._ //test in assembly := {} testOptions in Test += Tests.Argument(TestFrameworks.ScalaCheck, "-verbosity", "3") \ No newline at end of file diff --git a/src/main/scala/org/bitcoins/core/number/NumberType.scala b/src/main/scala/org/bitcoins/core/number/NumberType.scala index cdc20b1431..c8bdd9760b 100644 --- a/src/main/scala/org/bitcoins/core/number/NumberType.scala +++ b/src/main/scala/org/bitcoins/core/number/NumberType.scala @@ -94,6 +94,8 @@ sealed trait UInt32 extends UnsignedNumber with NumberOperations[UInt32] { */ sealed trait UInt64 extends UnsignedNumber with NumberOperations[UInt64] { override type A = BigInt + override def hex = encodeHex(underlying) + override def + (num : UInt64): UInt64 = { val sum = underlying + num.underlying val result = Try(UInt64(sum)) @@ -130,6 +132,19 @@ sealed trait UInt64 extends UnsignedNumber with NumberOperations[UInt64] { case Success(number) => number case Failure(exception) => throw exception } + + /** + * The converts a [[BigInt]] to a 8 byte hex representation + * [[BigInt]] will only allocate 1 byte for numbers like 1 which require 1 byte, giving us the hex representation 01 + * this function pads the hex chars to be 0000000000000001 + * @param bigInt + * @return + */ + private def encodeHex(bigInt : BigInt): String = { + val hex = BitcoinSUtil.encodeHex(bigInt) + val padding = for { _ <- 0 until 16 - hex.length} yield "0" + padding.mkString ++ hex + } } /** @@ -272,13 +287,13 @@ object UInt32 extends Factory[UInt32] with BitcoinSLogger with BaseNumbers[UInt3 object UInt64 extends Factory[UInt64] with BitcoinSLogger with BaseNumbers[UInt64] { - private case class UInt64Impl(underlying : BigInt, hex : String) extends UInt64 { + private case class UInt64Impl(underlying : BigInt) extends UInt64 { require(underlying >= 0, "We cannot have a negative number in an unsigned number: " + underlying) require(underlying <= BigInt("18446744073709551615"), "We cannot have a number larger than 2^64 -1 in UInt32, got: " + underlying) } - lazy val zero = UInt64(0) - lazy val one = UInt64(1) + lazy val zero = UInt64(BigInt(0)) + lazy val one = UInt64(BigInt(1)) lazy val min = zero lazy val max = fromBytes(Seq(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte, @@ -289,18 +304,14 @@ object UInt64 extends Factory[UInt64] with BitcoinSLogger with BaseNumbers[UInt6 (byte,index) <- bytes.reverse.zipWithIndex } yield NumberUtil.calculateUnsignedNumberFromByte(index, byte) logger.debug("Individual bytes values: " + individualByteValues) - UInt64Impl(individualByteValues.sum, BitcoinSUtil.encodeHex(bytes)) + UInt64Impl(individualByteValues.sum) } - def apply(num : BigInt): UInt64 = { - if (num >= (BigInt(1) << 63)) { - //since Scala uses twos complement, it will add a padding byte - //if the number is > 2^63. We can remove this since we want to - //represent this number as unsigned - val bytes = num.toByteArray.tail - UInt64Impl(num, BitcoinSUtil.encodeHex(bytes)) - } else UInt64Impl(num, BitcoinSUtil.encodeHex(num)) - } + def apply(num : BigInt): UInt64 = UInt64Impl(num) + + + + } diff --git a/src/test/scala/org/bitcoins/core/number/UInt64Test.scala b/src/test/scala/org/bitcoins/core/number/UInt64Test.scala index 388a147cb7..ecd6e516bb 100644 --- a/src/test/scala/org/bitcoins/core/number/UInt64Test.scala +++ b/src/test/scala/org/bitcoins/core/number/UInt64Test.scala @@ -9,9 +9,16 @@ class UInt64Test extends FlatSpec with MustMatchers { "UInt64" must "hold the number 0" in { val uInt64 = UInt64(Seq(0.toByte)) + uInt64.hex must be ("0000000000000000") uInt64.underlying must be (0) } + it must "encode the number 1" in { + val uInt64 = UInt64(1) + uInt64.underlying must be (1) + uInt64.hex must be ("0000000000000001") + } + it must "hold the max for a uint32_t" in { //this is UInt32_t's max value val uInt64 = UInt64(Seq(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))