diff --git a/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java b/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java
new file mode 100644
index 0000000..353f6ac
--- /dev/null
+++ b/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java
@@ -0,0 +1,69 @@
+package com.luminiasoft.bitshares;
+
+import com.google.common.primitives.Bytes;
+import com.google.common.primitives.UnsignedLong;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+/**
+ * Class used to encapsulate operations related to the account_update_operation.
+ */
+public class AccountUpdateOperation extends BaseOperation {
+ public static final String KEY_ACCOUNT = "account";
+ public static final String KEY_OWNER = "owner";
+ public static final String KEY_ACTIVE = "active";
+ public static final String KEY_FEE = "fee";
+ public static final String KEY_EXTENSIONS = "extensions";
+
+ private UserAccount account;
+ private AssetAmount fee;
+ private Authority owner;
+ private Authority active;
+ private Extensions extensions;
+
+ public AccountUpdateOperation(UserAccount account, Authority owner, Authority active, AssetAmount fee){
+ super(OperationType.account_update_operation);
+ this.account = account;
+ this.owner = owner;
+ this.active = active;
+ this.fee = fee;
+ extensions = new Extensions();
+ }
+
+ public AccountUpdateOperation(UserAccount account, Authority owner, Authority active){
+ this(account, owner, active, new AssetAmount(UnsignedLong.valueOf(0), new Asset("1.3.0")));
+ }
+
+ public void setFee(AssetAmount fee){
+ this.fee = fee;
+ }
+
+ @Override
+ public String toJsonString() {
+ Gson gson = new Gson();
+ return gson.toJson(this);
+ }
+
+ @Override
+ public JsonElement toJsonObject() {
+ JsonObject accountUpdate = new JsonObject();
+ accountUpdate.add(KEY_FEE, fee.toJsonObject());
+ accountUpdate.add(KEY_ACCOUNT, account.toJsonObject());
+ accountUpdate.add(KEY_OWNER, owner.toJsonObject());
+ accountUpdate.add(KEY_ACTIVE, active.toJsonObject());
+ accountUpdate.add(KEY_EXTENSIONS, extensions.toJsonObject());
+ return accountUpdate;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ byte[] feeBytes = fee.toBytes();
+ byte[] accountBytes = account.toBytes();
+ byte[] ownerBytes = owner.toBytes();
+ byte[] activeBytes = active.toBytes();
+ byte[] extensionBytes = extensions.toBytes();
+ return Bytes.concat(feeBytes, accountBytes, ownerBytes, activeBytes, extensionBytes);
+ }
+}
diff --git a/src/main/java/com/luminiasoft/bitshares/Authority.java b/src/main/java/com/luminiasoft/bitshares/Authority.java
index a9e9b18..98e991c 100644
--- a/src/main/java/com/luminiasoft/bitshares/Authority.java
+++ b/src/main/java/com/luminiasoft/bitshares/Authority.java
@@ -1,27 +1,32 @@
package com.luminiasoft.bitshares;
+import com.google.common.primitives.Bytes;
import com.google.gson.JsonElement;
import com.luminiasoft.bitshares.errors.MalformedAddressException;
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
-import java.util.HashMap;
+import java.nio.ByteBuffer;
+import java.util.*;
/**
* Created by nelson on 11/30/16.
*/
-public class Authority implements JsonSerializable {
+public class Authority implements JsonSerializable, ByteSerializable {
private long weight_threshold;
- private HashMap
address_auths;
- private HashMap account_auths;
- private HashMap key_auths;
+ private HashMap account_auths;
+ private HashMap key_auths;
+ private Extensions extensions;
- public Authority(HashMap keyAuths) throws MalformedAddressException {
- key_auths = new HashMap();
+ public Authority(long weight_threshold, HashMap keyAuths) throws MalformedAddressException {
+ this.weight_threshold = weight_threshold;
+ key_auths = new HashMap();
for(String key : keyAuths.keySet()){
Address address = new Address(key);
key_auths.put(address.getPublicKey(), keyAuths.get(key));
}
+ account_auths = new HashMap();
+ extensions = new Extensions();
}
@Override
@@ -33,4 +38,32 @@ public class Authority implements JsonSerializable {
public JsonElement toJsonObject() {
return null;
}
+
+ @Override
+ public byte[] toBytes() {
+ List byteArray = new ArrayList();
+ // Adding number of authorities
+ byteArray.add(Byte.valueOf((byte) (account_auths.size() + key_auths.size())));
+
+ // Weight threshold
+ byteArray.addAll(Bytes.asList(Util.revertInteger(new Integer((int) weight_threshold))));
+
+ // Number of account authorities
+ byteArray.add((byte) account_auths.size());
+
+ //TODO: Add account authorities
+
+ // Number of key authorities
+ byteArray.add((byte) key_auths.size());
+
+ for(PublicKey publicKey : key_auths.keySet()){
+ byteArray.addAll(Bytes.asList(publicKey.toBytes()));
+ byteArray.addAll(Bytes.asList(Util.revertShort(key_auths.get(publicKey).shortValue())));
+ }
+
+ // Adding number of extensions
+ byteArray.add((byte) extensions.size());
+
+ return Bytes.toArray(byteArray);
+ }
}
diff --git a/src/main/java/com/luminiasoft/bitshares/BaseOperation.java b/src/main/java/com/luminiasoft/bitshares/BaseOperation.java
index eaef155..414a88a 100644
--- a/src/main/java/com/luminiasoft/bitshares/BaseOperation.java
+++ b/src/main/java/com/luminiasoft/bitshares/BaseOperation.java
@@ -14,7 +14,9 @@ public abstract class BaseOperation implements ByteSerializable, JsonSerializabl
this.type = type;
}
- public abstract byte getId();
+ public byte getId() {
+ return (byte) this.type.ordinal();
+ }
public abstract byte[] toBytes();
}
diff --git a/src/main/java/com/luminiasoft/bitshares/Extension.java b/src/main/java/com/luminiasoft/bitshares/Extension.java
deleted file mode 100644
index f406bea..0000000
--- a/src/main/java/com/luminiasoft/bitshares/Extension.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.luminiasoft.bitshares;
-
-/**
- * Created by nelson on 11/9/16.
- */
-public class Extension {
- //TODO: Give this class a proper implementation
-}
diff --git a/src/main/java/com/luminiasoft/bitshares/Extensions.java b/src/main/java/com/luminiasoft/bitshares/Extensions.java
new file mode 100644
index 0000000..102dae8
--- /dev/null
+++ b/src/main/java/com/luminiasoft/bitshares/Extensions.java
@@ -0,0 +1,41 @@
+package com.luminiasoft.bitshares;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.luminiasoft.bitshares.interfaces.ByteSerializable;
+import com.luminiasoft.bitshares.interfaces.JsonSerializable;
+
+import java.util.ArrayList;
+
+/**
+ * Created by nelson on 11/9/16.
+ */
+public class Extensions implements JsonSerializable, ByteSerializable {
+ private ArrayList extensions;
+
+ public Extensions(){
+ extensions = new ArrayList<>();
+ }
+
+ @Override
+ public String toJsonString() {
+ return null;
+ }
+
+ @Override
+ public JsonElement toJsonObject() {
+ JsonArray array = new JsonArray();
+ for(JsonSerializable o : extensions)
+ array.add(o.toJsonObject());
+ return array;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return new byte[0];
+ }
+
+ public int size(){
+ return extensions.size();
+ }
+}
diff --git a/src/main/java/com/luminiasoft/bitshares/Main.java b/src/main/java/com/luminiasoft/bitshares/Main.java
index 69da478..c162eb3 100644
--- a/src/main/java/com/luminiasoft/bitshares/Main.java
+++ b/src/main/java/com/luminiasoft/bitshares/Main.java
@@ -49,7 +49,7 @@ public class Main {
// test.testTransactionBroadcastSequence();
// test.testAccountLookupDeserialization();
// test.testPrivateKeyManipulations();
- test.testPublicKeyManipulations();
+// test.testPublicKeyManipulations();
// test.testGetAccountByName();
// test.testGetRequiredFees();
// test.testRandomNumberGeneration();
@@ -61,5 +61,6 @@ public class Main {
// test.testingInvoiceGeneration();
// test.testCompression();
// test.testCreateBinFile();
+ test.testAccountUpdateOperationSerialization();
}
}
diff --git a/src/main/java/com/luminiasoft/bitshares/Test.java b/src/main/java/com/luminiasoft/bitshares/Test.java
index 8dba981..62ea660 100644
--- a/src/main/java/com/luminiasoft/bitshares/Test.java
+++ b/src/main/java/com/luminiasoft/bitshares/Test.java
@@ -743,4 +743,21 @@ public class Test {
byte[] fileOutput = FileBin.getBytesFromBrainKey(Main.BRAIN_KEY, "123456","bithon-83");
System.out.println("fileOutput " + Arrays.toString(fileOutput));
}
+
+ public void testAccountUpdateOperationSerialization(){
+ UserAccount account = new UserAccount("1.2.138632");
+ AssetAmount fee = new AssetAmount(UnsignedLong.valueOf("4294967295"), new Asset("1.3.0"));
+ HashMap keyAuths = new HashMap<>();
+ keyAuths.put("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY", 65535);
+ try {
+ Authority owner = new Authority(1, keyAuths);
+ Authority active = new Authority(1, keyAuths);
+ AccountUpdateOperation operation = new AccountUpdateOperation(account, owner, active, fee);
+ byte[] serializedOperation = operation.toBytes();
+ System.out.println("serialized operation");
+ System.out.println(Util.bytesToHex(serializedOperation));
+ } catch (MalformedAddressException e) {
+ System.out.println("MalformedAddressException. Msg: "+e.getMessage());
+ }
+ }
}
diff --git a/src/main/java/com/luminiasoft/bitshares/Transaction.java b/src/main/java/com/luminiasoft/bitshares/Transaction.java
index e0f4341..109bb98 100644
--- a/src/main/java/com/luminiasoft/bitshares/Transaction.java
+++ b/src/main/java/com/luminiasoft/bitshares/Transaction.java
@@ -38,7 +38,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
private ECKey privateKey;
private BlockData blockData;
private List operations;
- private List extensions;
+ private List extensions;
/**
* Transaction constructor.
@@ -50,7 +50,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
this.privateKey = DumpedPrivateKey.fromBase58(null, wif).getKey();
this.blockData = block_data;
this.operations = operation_list;
- this.extensions = new ArrayList();
+ this.extensions = new ArrayList();
}
/**
@@ -63,7 +63,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
this.privateKey = privateKey;
this.blockData = blockData;
this.operations = operationList;
- this.extensions = new ArrayList();
+ this.extensions = new ArrayList();
}
public ECKey getPrivateKey(){
@@ -143,8 +143,8 @@ public class Transaction implements ByteSerializable, JsonSerializable {
//Adding the number of extensions
byteArray.add((byte) this.extensions.size());
- for(Extension extension : extensions){
- //TODO: Implement the extension serialization
+ for(Extensions extensions : this.extensions){
+ //TODO: Implement the extensions serialization
}
// Adding a last zero byte to match the result obtained by the python-graphenelib code
// I'm not exactly sure what's the meaning of this last zero byte, but for now I'll just
diff --git a/src/main/java/com/luminiasoft/bitshares/TransferOperation.java b/src/main/java/com/luminiasoft/bitshares/TransferOperation.java
index 3940e66..87692a2 100644
--- a/src/main/java/com/luminiasoft/bitshares/TransferOperation.java
+++ b/src/main/java/com/luminiasoft/bitshares/TransferOperation.java
@@ -44,11 +44,6 @@ public class TransferOperation extends BaseOperation {
this.fee = newFee;
}
- @Override
- public byte getId() {
- return (byte) this.type.ordinal();
- }
-
public UserAccount getFrom(){
return this.from;
}
@@ -77,6 +72,7 @@ public class TransferOperation extends BaseOperation {
@Override
public String toJsonString() {
+ //TODO: Evaluate using simple Gson class to return a simple string representation and drop the TransferSerializer class
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(TransferOperation.class, new TransferSerializer());
return gsonBuilder.create().toJson(this);
diff --git a/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java b/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java
index 97d07a2..10be1f7 100644
--- a/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java
+++ b/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java
@@ -46,6 +46,7 @@ public class TransferTransactionBuilder extends TransactionBuilder {
return this;
}
+ //TODO: Add support for multiple transfer operations in a single transaction
public TransferTransactionBuilder addOperation(TransferOperation transferOperation){
if(operations == null){
operations = new ArrayList();
diff --git a/src/main/java/com/luminiasoft/bitshares/Util.java b/src/main/java/com/luminiasoft/bitshares/Util.java
index a333deb..f02fbbe 100644
--- a/src/main/java/com/luminiasoft/bitshares/Util.java
+++ b/src/main/java/com/luminiasoft/bitshares/Util.java
@@ -1,5 +1,6 @@
package com.luminiasoft.bitshares;
+import com.google.common.primitives.Bytes;
import org.tukaani.xz.LZMA2Options;
import org.tukaani.xz.LZMAInputStream;
import org.tukaani.xz.LZMAOutputStream;
@@ -7,6 +8,7 @@ import org.tukaani.xz.LZMAOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.tukaani.xz.XZOutputStream;
@@ -99,4 +101,33 @@ public class Util {
}
return null;
}
+
+ /**
+ * Returns an array of bytes with the underlying data used to represent an integer in the reverse form.
+ * This is useful for endianess switches, meaning that if you give this function a big-endian integer
+ * it will return it's little-endian bytes.
+ * @param input An Integer value.
+ * @return The array of bytes that represent this value in the reverse format.
+ */
+ public static byte[] revertInteger(Integer input){
+ return ByteBuffer.allocate(Integer.BYTES).putInt(Integer.reverseBytes(input)).array();
+ }
+
+ /**
+ * Same operation as in the revertInteger function, but in this case for a short (2 bytes) value.
+ * @param input A Short value
+ * @return The array of bytes that represent this value in the reverse format.
+ */
+ public static byte[] revertShort(Short input){
+ return ByteBuffer.allocate(Short.BYTES).putShort(Short.reverseBytes(input)).array();
+ }
+
+ /**
+ * Same operation as in the revertInteger function, but in this case for a long (8 bytes) value.
+ * @param input A Long value
+ * @return The array of bytes that represent this value in the reverse format.
+ */
+ public static byte[] revertLong(Long input){
+ return ByteBuffer.allocate(Long.BYTES).putLong(Long.reverseBytes(input)).array();
+ }
}