From 88ca47c37837d38045d9bc76ce57bd7466cfa383 Mon Sep 17 00:00:00 2001 From: "Nelson R. Perez" Date: Wed, 19 Apr 2017 22:22:57 -0500 Subject: [PATCH] Fixing a problem caused by the lack of extension byte in the serialization of the AccountOption class --- .../graphenej/AccountOptions.java | 15 +++- .../bitsharesmunich/graphenej/BrainKey.java | 18 +++++ .../bitsharesmunich/graphenej/Optional.java | 11 ++- .../operations/AccountUpdateOperation.java | 1 - .../graphenej/BrainKeyTest.java | 30 +++++++ .../AccountUpdateOperationTest.java | 80 +++++++++++++++++++ 6 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 graphenej/src/test/java/de/bitsharesmunich/graphenej/BrainKeyTest.java create mode 100644 graphenej/src/test/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationTest.java diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountOptions.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountOptions.java index 8206591..43c060e 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountOptions.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountOptions.java @@ -1,14 +1,20 @@ package de.bitsharesmunich.graphenej; import com.google.common.primitives.Bytes; -import com.google.gson.*; -import de.bitsharesmunich.graphenej.errors.MalformedAddressException; -import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable; +import com.google.gson.JsonArray; +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 java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import de.bitsharesmunich.graphenej.errors.MalformedAddressException; +import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable; + /** * Created by nelson on 12/5/16. */ @@ -107,6 +113,9 @@ public class AccountOptions implements GrapheneSerializable { //TODO: Check this serialization byteArray.addAll(Bytes.asList(vote.toBytes())); } + + // Account options's extensions + byteArray.addAll(Bytes.asList(extensions.toBytes())); }else{ byteArray.add((byte) 0); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/BrainKey.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/BrainKey.java index 860559c..7812ee9 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/BrainKey.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/BrainKey.java @@ -110,10 +110,28 @@ public class BrainKey { return wif.toString(); } + /** + * Returns the public address derived from this brain key + * @param prefix: The prefix to use in this address. + * @return An instance of the {@link Address} class + */ + public Address getPublicAddress(String prefix){ + return new Address(ECKey.fromPublicOnly(getPublicKey()), prefix); + } + + /** + * Brain key words getter + * @return: The word sequence that comprises this brain key + */ public String getBrainKey(){ return mBrainKey; } + /** + * Sequence number getter + * @return: The sequence number used alongside with the brain key words in order + * to derive the private key + */ public int getSequenceNumber(){ return sequenceNumber; } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/Optional.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/Optional.java index cc02c7b..8f48c5e 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/Optional.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/Optional.java @@ -1,10 +1,19 @@ package de.bitsharesmunich.graphenej; import com.google.gson.JsonElement; + +import de.bitsharesmunich.graphenej.interfaces.ByteSerializable; import de.bitsharesmunich.graphenej.interfaces.GrapheneSerializable; /** - * Used whenever we have an optional field. + * Container template class used whenever we have an optional field. + * + * The idea here is that the binary serialization of this field should be performed + * in a specific way determined by the field implementing the {@link ByteSerializable} + * interface, more specifically using the {@link ByteSerializable#toBytes()} method. + * + * However, if the field is missing, the Optional class should be able to know how + * to serialize it, as this is always done by placing an zero byte. */ public class Optional implements GrapheneSerializable { private T optionalField; diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java index 5abe334..5798f2e 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java @@ -24,7 +24,6 @@ public class AccountUpdateOperation extends BaseOperation { private Optional owner; private Optional active; private Optional new_options; - private Extensions extensions; /** * Account update operation constructor. diff --git a/graphenej/src/test/java/de/bitsharesmunich/graphenej/BrainKeyTest.java b/graphenej/src/test/java/de/bitsharesmunich/graphenej/BrainKeyTest.java new file mode 100644 index 0000000..e423a6b --- /dev/null +++ b/graphenej/src/test/java/de/bitsharesmunich/graphenej/BrainKeyTest.java @@ -0,0 +1,30 @@ +package de.bitsharesmunich.graphenej; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * Created by nelson on 4/18/17. + */ +public class BrainKeyTest { +// public final String TEST_BRAINKEY = "SOAPILY GASSING FIFIE OZONATE WHYO TOPLINE PRISMY ZEUGMA GLOTTIC DAVEN CORODY PFUI"; + public final String TEST_BRAINKEY = "BARIC BICKERN LITZ TIPFUL JINGLED POOL TUMBAK PURIST APOPYLE DURAIN SATLIJK FAUCAL"; + private BrainKey mBrainKey; + + @Before + public void setup(){ + mBrainKey = new BrainKey(TEST_BRAINKEY, BrainKey.DEFAULT_SEQUENCE_NUMBER); + } + + @Test + public void testAddress(){ + Address address = mBrainKey.getPublicAddress(Address.BITSHARES_PREFIX); +// Assert.assertEquals("Assert that the address created is the expected one", +// "BTS7yT2vnjGAxPocqsnDfoJv3DHUtCNGWwqvc7mWRikkqwuhKtT5s", +// address.toString()); + Assert.assertEquals("Assert that the address created is the expected one", + "BTS61UqqgE3ARuTGcckzARsdQm4EMFdBEwYyi1pbwyHrZZWrCDhT2", + address.toString()); + } +} \ No newline at end of file diff --git a/graphenej/src/test/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationTest.java b/graphenej/src/test/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationTest.java new file mode 100644 index 0000000..529470f --- /dev/null +++ b/graphenej/src/test/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationTest.java @@ -0,0 +1,80 @@ +package de.bitsharesmunich.graphenej.operations; + +import com.google.common.primitives.UnsignedLong; + +import org.bitcoinj.core.ECKey; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; + +import de.bitsharesmunich.graphenej.AccountOptions; +import de.bitsharesmunich.graphenej.Address; +import de.bitsharesmunich.graphenej.Asset; +import de.bitsharesmunich.graphenej.AssetAmount; +import de.bitsharesmunich.graphenej.Authority; +import de.bitsharesmunich.graphenej.BaseOperation; +import de.bitsharesmunich.graphenej.BlockData; +import de.bitsharesmunich.graphenej.BrainKey; +import de.bitsharesmunich.graphenej.PublicKey; +import de.bitsharesmunich.graphenej.Transaction; +import de.bitsharesmunich.graphenej.UserAccount; +import de.bitsharesmunich.graphenej.Util; +import de.bitsharesmunich.graphenej.errors.MalformedAddressException; + +/** + * Created by nelson on 4/18/17. + */ +public class AccountUpdateOperationTest { + + private static final String BILTHON_16_BRAIN_KEY = "SOAPILY GASSING FIFIE OZONATE WHYO TOPLINE PRISMY ZEUGMA GLOTTIC DAVEN CORODY PFUI"; + public final String ADDRESS = "BTS8RYD5ehEMtTrfmeWRVKJzvLK2AqunxRh2XhXyXVxKtDjeAhYs1"; + + private final Asset CORE = new Asset("1.3.0"); + + private Authority active; + private AccountOptions options; + + @Before + public void setup(){ + try{ + HashMap keyAuth = new HashMap<>(); + keyAuth.put(new Address(ADDRESS), 1); + active = new Authority(); + active.setKeyAuthorities(keyAuth); + + options = new AccountOptions(); + options.setMemoKey(new PublicKey(ECKey.fromPublicOnly(new Address(ADDRESS).getPublicKey().toBytes()))); + options.setNumWitness(0); + options.setNum_comittee(0); + options.setVotingAccount(new UserAccount("1.2.5")); + }catch(MalformedAddressException e){ + System.out.println("MalformedAddressException. Msg: "+e.getMessage()); + } + } + + @Test + public void testOperationSerialization(){ + AccountUpdateOperationBuilder builder = new AccountUpdateOperationBuilder() + .setAccount(new UserAccount("1.2.143569")) + .setFee(new AssetAmount(UnsignedLong.valueOf(14676), CORE)) + .setActive(active) + .setOptions(options); + + AccountUpdateOperation operation = builder.build(); + + ArrayList operations = new ArrayList<>(); + operations.add(operation); + ECKey privateKey = new BrainKey(BILTHON_16_BRAIN_KEY, 0).getPrivateKey(); + BlockData blockData = new BlockData(3703, 2015738269, 1492551764); + + Transaction tx = new Transaction(privateKey, blockData, operations); + +// String json = tx.toJsonString(); + byte[] serialized = tx.toBytes(); + +// System.out.println("json: "+json); + System.out.println("serialized: "+ Util.bytesToHex(serialized)); + } +} \ No newline at end of file