From b305faa6625403e4321740e77c0906d34bfe22f6 Mon Sep 17 00:00:00 2001 From: "Nelson R. Perez" Date: Thu, 12 Oct 2017 23:34:22 -0500 Subject: [PATCH] Fixing a bug with memo deserialization --- .../main/java/cy/agorise/graphenej/Util.java | 33 ++++++++++++++----- .../cy/agorise/graphenej/objects/Memo.java | 31 +++++++++-------- .../cy/agorise/graphenej/TransactionTest.java | 30 ++++++++++------- .../java/cy/agorise/graphenej/UtilTest.java | 21 ++++++++++++ .../agorise/graphenej/objects/MemoTest.java | 14 +++++--- 5 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 graphenej/src/test/java/cy/agorise/graphenej/UtilTest.java diff --git a/graphenej/src/main/java/cy/agorise/graphenej/Util.java b/graphenej/src/main/java/cy/agorise/graphenej/Util.java index 848d89f..d746ed0 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/Util.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/Util.java @@ -1,7 +1,22 @@ package cy.agorise.graphenej; import com.google.common.primitives.Bytes; -import org.tukaani.xz.*; +import com.google.common.primitives.UnsignedLong; + +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.tukaani.xz.CorruptedInputException; +import org.tukaani.xz.FinishableOutputStream; +import org.tukaani.xz.LZMA2Options; +import org.tukaani.xz.LZMAInputStream; +import org.tukaani.xz.LZMAOutputStream; +import org.tukaani.xz.XZInputStream; +import org.tukaani.xz.XZOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -13,13 +28,6 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; -import org.spongycastle.crypto.DataLengthException; -import org.spongycastle.crypto.InvalidCipherTextException; -import org.spongycastle.crypto.engines.AESFastEngine; -import org.spongycastle.crypto.modes.CBCBlockCipher; -import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; -import org.spongycastle.crypto.params.KeyParameter; -import org.spongycastle.crypto.params.ParametersWithIV; /** * Class used to encapsulate common utility methods @@ -210,6 +218,15 @@ public class Util { return ByteBuffer.allocate(Long.SIZE / 8).putLong(Long.reverseBytes(input)).array(); } + /** + * Same operation as in the revertInteger function, but with an UnsignedLong object as argument. + * @param input An UnsignedLong class instance + * @return The array of bytes that represent this value in the reverse format. + */ + public static byte[] revertUnsignedLong(UnsignedLong input){ + return ByteBuffer.allocate(Long.SIZE / 8).putLong(Long.reverseBytes(input.longValue())).array(); + } + public static byte[] revertBytes(byte[] array){ byte[] reverted = new byte[array.length]; for(int i = 0; i < reverted.length; i++){ diff --git a/graphenej/src/main/java/cy/agorise/graphenej/objects/Memo.java b/graphenej/src/main/java/cy/agorise/graphenej/objects/Memo.java index 353640e..b979e55 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/objects/Memo.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/objects/Memo.java @@ -1,20 +1,13 @@ package cy.agorise.graphenej.objects; import com.google.common.primitives.Bytes; +import com.google.common.primitives.UnsignedLong; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import cy.agorise.graphenej.Address; -import cy.agorise.graphenej.PublicKey; -import cy.agorise.graphenej.Util; -import cy.agorise.graphenej.errors.ChecksumException; -import cy.agorise.graphenej.errors.MalformedAddressException; -import cy.agorise.graphenej.interfaces.ByteSerializable; -import cy.agorise.graphenej.interfaces.JsonSerializable; - import org.bitcoinj.core.ECKey; import org.spongycastle.math.ec.ECPoint; @@ -23,8 +16,17 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import cy.agorise.graphenej.Address; +import cy.agorise.graphenej.PublicKey; +import cy.agorise.graphenej.Util; +import cy.agorise.graphenej.errors.ChecksumException; +import cy.agorise.graphenej.errors.MalformedAddressException; +import cy.agorise.graphenej.interfaces.ByteSerializable; +import cy.agorise.graphenej.interfaces.JsonSerializable; + /** - * Created by nelson on 11/9/16. + * Class used to represent a memo data structure + * {@url https://bitshares.org/doxygen/structgraphene_1_1chain_1_1memo__data.html} */ public class Memo implements ByteSerializable, JsonSerializable { public final static String TAG = "Memo"; @@ -35,7 +37,7 @@ public class Memo implements ByteSerializable, JsonSerializable { private Address from; private Address to; - private long nonce; + private UnsignedLong nonce; private byte[] message; private String plaintextMessage; @@ -66,7 +68,7 @@ public class Memo implements ByteSerializable, JsonSerializable { * @param nonce: Nonce used in the encryption. * @param message: Message in ciphertext. */ - public Memo(Address from, Address to, long nonce, byte[] message){ + public Memo(Address from, Address to, UnsignedLong nonce, byte[] message){ this.from = from; this.to = to; this.nonce = nonce; @@ -89,7 +91,7 @@ public class Memo implements ByteSerializable, JsonSerializable { return this.to; } - public long getNonce(){ + public UnsignedLong getNonce(){ return this.nonce; } @@ -235,7 +237,7 @@ public class Memo implements ByteSerializable, JsonSerializable { new byte[]{(byte) this.message.length}, this.message); } else { - byte[] nonceBytes = Util.revertLong(nonce); + byte[] nonceBytes = Util.revertUnsignedLong(nonce); ECPoint senderPoint = ECKey.compressPoint(from.getPublicKey().getKey().getPubKeyPoint()); PublicKey senderPublicKey = new PublicKey(ECKey.fromPublicOnly(senderPoint)); @@ -287,7 +289,7 @@ public class Memo implements ByteSerializable, JsonSerializable { JsonObject jsonObject = json.getAsJsonObject(); String fromAddress = jsonObject.get(KEY_FROM).getAsString(); String toAddress = jsonObject.get(KEY_TO).getAsString(); - long nonce = jsonObject.get(KEY_NONCE).getAsLong(); + UnsignedLong nonce = UnsignedLong.valueOf(jsonObject.get(KEY_NONCE).getAsString()); String msg = jsonObject.get(KEY_MESSAGE).getAsString(); Memo memo = null; @@ -295,6 +297,7 @@ public class Memo implements ByteSerializable, JsonSerializable { Address from = new Address(fromAddress); Address to = new Address(toAddress); byte[] message = Util.hexToBytes(msg); + memo = new Memo(from, to, nonce, message); }catch(MalformedAddressException e){ System.out.println("MalformedAddressException. Msg: "+e.getMessage()); diff --git a/graphenej/src/test/java/cy/agorise/graphenej/TransactionTest.java b/graphenej/src/test/java/cy/agorise/graphenej/TransactionTest.java index bf4ded1..f211c6f 100644 --- a/graphenej/src/test/java/cy/agorise/graphenej/TransactionTest.java +++ b/graphenej/src/test/java/cy/agorise/graphenej/TransactionTest.java @@ -4,24 +4,30 @@ import com.google.common.primitives.UnsignedLong; import com.neovisionaries.ws.client.WebSocket; import com.neovisionaries.ws.client.WebSocketException; import com.neovisionaries.ws.client.WebSocketFactory; + +import org.bitcoinj.core.ECKey; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.SSLContext; + import cy.agorise.graphenej.api.GetLimitOrders; import cy.agorise.graphenej.api.TransactionBroadcastSequence; import cy.agorise.graphenej.interfaces.WitnessResponseListener; import cy.agorise.graphenej.models.BaseResponse; import cy.agorise.graphenej.models.WitnessResponse; import cy.agorise.graphenej.objects.Memo; -import cy.agorise.graphenej.operations.*; +import cy.agorise.graphenej.operations.LimitOrderCancelOperation; +import cy.agorise.graphenej.operations.LimitOrderCreateOperation; +import cy.agorise.graphenej.operations.TransferOperation; +import cy.agorise.graphenej.operations.TransferOperationBuilder; import cy.agorise.graphenej.test.NaiveSSLContext; -import org.bitcoinj.core.ECKey; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import javax.net.ssl.SSLContext; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.List; /** * Created by nelson on 3/6/17. @@ -138,7 +144,7 @@ public class TransactionTest { // Creating memo long nonce = 1; byte[] encryptedMessage = Memo.encryptMessage(sourcePrivateKey, to1, nonce, "another message"); - Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), nonce, encryptedMessage); + Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), UnsignedLong.valueOf(nonce), encryptedMessage); // Creating operation 1 TransferOperation transferOperation1 = new TransferOperationBuilder() diff --git a/graphenej/src/test/java/cy/agorise/graphenej/UtilTest.java b/graphenej/src/test/java/cy/agorise/graphenej/UtilTest.java new file mode 100644 index 0000000..9ba1d90 --- /dev/null +++ b/graphenej/src/test/java/cy/agorise/graphenej/UtilTest.java @@ -0,0 +1,21 @@ +package cy.agorise.graphenej; + +import com.google.common.primitives.UnsignedLong; + +import junit.framework.Assert; + +import org.junit.Test; + +/** + * Class used to test Util methods + */ + +public class UtilTest { + + @Test + public void testRevertUnsignedLong(){ + UnsignedLong unsignedLong = UnsignedLong.valueOf("12179241258665439971"); + byte[] reversed = Util.revertUnsignedLong(unsignedLong); + Assert.assertEquals("e3f28878655b05a9", Util.bytesToHex(reversed)); + } +} diff --git a/graphenej/src/test/java/cy/agorise/graphenej/objects/MemoTest.java b/graphenej/src/test/java/cy/agorise/graphenej/objects/MemoTest.java index fa787e0..e469578 100644 --- a/graphenej/src/test/java/cy/agorise/graphenej/objects/MemoTest.java +++ b/graphenej/src/test/java/cy/agorise/graphenej/objects/MemoTest.java @@ -1,14 +1,18 @@ package cy.agorise.graphenej.objects; +import com.google.common.primitives.UnsignedLong; import com.google.gson.JsonElement; import com.google.gson.JsonObject; + +import org.bitcoinj.core.DumpedPrivateKey; +import org.bitcoinj.core.ECKey; +import org.junit.Before; +import org.junit.Test; + import cy.agorise.graphenej.Address; import cy.agorise.graphenej.PublicKey; import cy.agorise.graphenej.Util; import cy.agorise.graphenej.errors.ChecksumException; -import org.bitcoinj.core.DumpedPrivateKey; -import org.bitcoinj.core.ECKey; -import org.junit.*; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -130,7 +134,7 @@ public class MemoTest { @Test public void shouldBeJsonObjectSerializable(){ byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); - Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted); + Memo memo = new Memo(sourceAddress, destinationAddress, UnsignedLong.ONE, encrypted); JsonElement jsonObject = memo.toJsonObject(); JsonObject reference = new JsonObject(); reference.addProperty("from", "BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); @@ -144,7 +148,7 @@ public class MemoTest { public void shouldBeByteSerializable(){ String byteReference = "0103d1fb8c7421db64d46fba7e36f428854ca06eff65698b293f37c7ffaa54e2c2b203aece7c31616c02fcc96b50d3397c0e8d33d6384655d477c300d9196c728a5ee20100000000000000104c81c2db6ebc61e3f9e0ead65c0559dd"; byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); - Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted); + Memo memo = new Memo(sourceAddress, destinationAddress, UnsignedLong.ONE, encrypted); byte[] memoBytes = memo.toBytes(); assertEquals("Memo instance should generate a valid byte array", byteReference, Util.bytesToHex(memoBytes)); }