From 16d3ff6721a9d870693f542c29db29ab2ede8b63 Mon Sep 17 00:00:00 2001 From: Kostya Shpachenko Date: Wed, 13 Dec 2017 23:55:00 +0200 Subject: [PATCH] Implemented support of custom operation --- .../main/java/cy/agorise/graphenej/Util.java | 22 ++++ .../graphenej/operations/CustomOperation.java | 124 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/operations/CustomOperation.java diff --git a/graphenej/src/main/java/cy/agorise/graphenej/Util.java b/graphenej/src/main/java/cy/agorise/graphenej/Util.java index d746ed0..4f80a85 100644 --- a/graphenej/src/main/java/cy/agorise/graphenej/Util.java +++ b/graphenej/src/main/java/cy/agorise/graphenej/Util.java @@ -26,6 +26,8 @@ import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -92,6 +94,26 @@ public class Util { return buffer.array(); } + /** + * Serializes long value to a byte array. + * @param data Long value. + * @return Array of bytes. + */ + public static byte[] serializeLongToBytes(long data) { + List bytes = new LinkedList<>(); + long value = data; + do { + byte b = (byte)(value & 0x7F); + value >>= 7; + if (value != 0) { + b |= 0x80; + } + bytes.add(b); + } while (value != 0); + + return Bytes.toArray(bytes); + } + /** * Utility function that compresses data using the LZMA algorithm. * @param inputBytes Input bytes of the data to be compressed. diff --git a/graphenej/src/main/java/cy/agorise/graphenej/operations/CustomOperation.java b/graphenej/src/main/java/cy/agorise/graphenej/operations/CustomOperation.java new file mode 100644 index 0000000..de4d091 --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/operations/CustomOperation.java @@ -0,0 +1,124 @@ +package cy.agorise.graphenej.operations; + +import com.google.common.primitives.Bytes; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import cy.agorise.graphenej.*; + +import java.util.LinkedList; +import java.util.List; + +public class CustomOperation extends BaseOperation { + private static final String KEY_FEE = "fee"; + private static final String KEY_PAYER = "payer"; + private static final String KEY_REQUIRED_AUTH = "required_auths"; + private static final String KEY_ID = "id"; + private static final String KEY_DATA = "data"; + + private AssetAmount fee; + private UserAccount payer; + private List requiredAuths; + private int operationId; + private String data; + + public CustomOperation(AssetAmount fee, UserAccount payer, int operationId, List requiredAuths, String data) { + super(OperationType.CUSTOM_OPERATION); + this.fee = fee; + this.payer = payer; + this.operationId = operationId; + this.requiredAuths = new LinkedList<>(); + if (requiredAuths != null) { + this.requiredAuths.addAll(requiredAuths); + } + this.data = data; + } + + public AssetAmount getFee() { + return fee; + } + + @Override + public void setFee(AssetAmount fee) { + this.fee = fee; + } + + public UserAccount getPayer() { + return payer; + } + + public void setPayer(UserAccount payer) { + this.payer = payer; + } + + public List getRequiredAuths() { + return requiredAuths; + } + + public void setRequiredAuths(List requiredAuths) { + this.requiredAuths = requiredAuths; + } + + public int getOperationId() { + return operationId; + } + + public void setOperationId(int operationId) { + this.operationId = operationId; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + @Override + public byte[] toBytes() { + byte[] feeBytes = fee.toBytes(); + byte[] payerBytes = payer.toBytes(); + List requiredAuthsSerialized = new LinkedList<>(); + if (this.requiredAuths != null) { + for (UserAccount userAccount : this.requiredAuths) { + requiredAuthsSerialized.addAll(Bytes.asList(userAccount.toBytes())); + } + } + byte[] requiredAuthsBytes = Bytes.toArray(requiredAuthsSerialized); + byte[] requiredAuthsLength = {(byte)this.requiredAuths.size()}; + byte[] operationIdBytes = Util.revertShort((short)operationId); + byte[] dataLength = Util.serializeLongToBytes(data.length()); + byte[] dataBytes = Util.hexlify(data); + + return Bytes.concat(feeBytes, payerBytes, requiredAuthsLength, requiredAuthsBytes, operationIdBytes, dataLength, dataBytes); + } + + @Override + public String toJsonString() { + return toJsonObject().toString(); + } + + @Override + public JsonElement toJsonObject() { + JsonArray array = new JsonArray(); + array.add(this.getId()); + + JsonObject jsonObject = new JsonObject(); + jsonObject.add(KEY_FEE, fee.toJsonObject()); + jsonObject.addProperty(KEY_PAYER, payer.getObjectId()); + JsonArray requiredAuthArray = new JsonArray(); + if (requiredAuths != null) { + for (UserAccount userAccount : requiredAuths) { + requiredAuthArray.add(userAccount.getObjectId()); + } + } + jsonObject.add(KEY_REQUIRED_AUTH, requiredAuthArray); + jsonObject.addProperty(KEY_ID, operationId); + jsonObject.addProperty(KEY_DATA, Util.bytesToHex(Util.hexlify(data))); + + array.add(jsonObject); + + return array; + } +}