From a68caa2de112f2da06a6aa81e69b0949ff713614 Mon Sep 17 00:00:00 2001 From: catbref Date: Mon, 24 Feb 2020 13:51:01 +0000 Subject: [PATCH] Fix serialization of negative BigDecimal values! We've never needed this before but now it's fixed. Added corresponding +ve & -ve tests just to make sure. Only actual use-case that comes to mind is cancelling reward-share. --- .../java/org/qortal/utils/Serialization.java | 8 +++++ .../org/qortal/test/SerializationTests.java | 30 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/main/java/org/qortal/utils/Serialization.java b/src/main/java/org/qortal/utils/Serialization.java index 27852ca0..e9bf6e0e 100644 --- a/src/main/java/org/qortal/utils/Serialization.java +++ b/src/main/java/org/qortal/utils/Serialization.java @@ -7,6 +7,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import org.qortal.transform.TransformationException; import org.qortal.transform.Transformer; @@ -28,7 +29,14 @@ public class Serialization { // (At least until the BigDecimal XmlAdapter works - see data/package-info.java) byte[] amountBytes = amount.setScale(8).unscaledValue().toByteArray(); byte[] output = new byte[length]; + + // To retain sign of 'amount', we might need to explicitly fill 'output' with leading 1s + if (amount.signum() == -1) + // Negative values: fill output with 1s + Arrays.fill(output, (byte) 0xff); + System.arraycopy(amountBytes, 0, output, length - amountBytes.length, amountBytes.length); + return output; } diff --git a/src/test/java/org/qortal/test/SerializationTests.java b/src/test/java/org/qortal/test/SerializationTests.java index 0f4fb2c4..7f8b0780 100644 --- a/src/test/java/org/qortal/test/SerializationTests.java +++ b/src/test/java/org/qortal/test/SerializationTests.java @@ -12,6 +12,7 @@ import org.qortal.transaction.Transaction; import org.qortal.transform.TransformationException; import org.qortal.transform.transaction.TransactionTransformer; import org.qortal.utils.Base58; +import org.qortal.utils.Serialization; import com.google.common.hash.HashCode; @@ -19,6 +20,9 @@ import io.druid.extendedset.intset.ConciseSet; import static org.junit.Assert.*; +import java.io.IOException; +import java.math.BigDecimal; +import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; import java.util.Random; @@ -142,4 +146,30 @@ public class SerializationTests extends Common { } } + @Test + public void testPositiveBigDecimal() throws IOException { + BigDecimal amount = new BigDecimal("123.4567").setScale(8); + + byte[] bytes = Serialization.serializeBigDecimal(amount); + assertEquals("Serialized BigDecimal should be 8 bytes long", 8, bytes.length); + + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + BigDecimal newAmount = Serialization.deserializeBigDecimal(byteBuffer); + + assertEqualBigDecimals("Deserialized BigDecimal has incorrect value", amount, newAmount); + } + + @Test + public void testNegativeBigDecimal() throws IOException { + BigDecimal amount = new BigDecimal("-1.23").setScale(8); + + byte[] bytes = Serialization.serializeBigDecimal(amount); + assertEquals("Serialized BigDecimal should be 8 bytes long", 8, bytes.length); + + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + BigDecimal newAmount = Serialization.deserializeBigDecimal(byteBuffer); + + assertEqualBigDecimals("Deserialized BigDecimal has incorrect value", amount, newAmount); + } + } \ No newline at end of file