Introducing the class AccountUpdateOperation
This commit is contained in:
parent
8b81c30fa9
commit
5c449da04f
11 changed files with 210 additions and 27 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,27 +1,32 @@
|
||||||
package com.luminiasoft.bitshares;
|
package com.luminiasoft.bitshares;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.luminiasoft.bitshares.errors.MalformedAddressException;
|
import com.luminiasoft.bitshares.errors.MalformedAddressException;
|
||||||
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
import com.luminiasoft.bitshares.interfaces.ByteSerializable;
|
||||||
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
|
import com.luminiasoft.bitshares.interfaces.JsonSerializable;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by nelson on 11/30/16.
|
* Created by nelson on 11/30/16.
|
||||||
*/
|
*/
|
||||||
public class Authority implements JsonSerializable {
|
public class Authority implements JsonSerializable, ByteSerializable {
|
||||||
private long weight_threshold;
|
private long weight_threshold;
|
||||||
private HashMap<Address, Long> address_auths;
|
private HashMap<UserAccount, Integer> account_auths;
|
||||||
private HashMap<UserAccount, Long> account_auths;
|
private HashMap<PublicKey, Integer> key_auths;
|
||||||
private HashMap<PublicKey, Long> key_auths;
|
private Extensions extensions;
|
||||||
|
|
||||||
public Authority(HashMap<String, Long> keyAuths) throws MalformedAddressException {
|
public Authority(long weight_threshold, HashMap<String, Integer> keyAuths) throws MalformedAddressException {
|
||||||
key_auths = new HashMap<PublicKey, Long>();
|
this.weight_threshold = weight_threshold;
|
||||||
|
key_auths = new HashMap<PublicKey, Integer>();
|
||||||
for(String key : keyAuths.keySet()){
|
for(String key : keyAuths.keySet()){
|
||||||
Address address = new Address(key);
|
Address address = new Address(key);
|
||||||
key_auths.put(address.getPublicKey(), keyAuths.get(key));
|
key_auths.put(address.getPublicKey(), keyAuths.get(key));
|
||||||
}
|
}
|
||||||
|
account_auths = new HashMap<UserAccount, Integer>();
|
||||||
|
extensions = new Extensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,4 +38,32 @@ public class Authority implements JsonSerializable {
|
||||||
public JsonElement toJsonObject() {
|
public JsonElement toJsonObject() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes() {
|
||||||
|
List<Byte> byteArray = new ArrayList<Byte>();
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ public abstract class BaseOperation implements ByteSerializable, JsonSerializabl
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract byte getId();
|
public byte getId() {
|
||||||
|
return (byte) this.type.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
public abstract byte[] toBytes();
|
public abstract byte[] toBytes();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
41
src/main/java/com/luminiasoft/bitshares/Extensions.java
Normal file
41
src/main/java/com/luminiasoft/bitshares/Extensions.java
Normal file
|
@ -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<JsonSerializable> 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ public class Main {
|
||||||
// test.testTransactionBroadcastSequence();
|
// test.testTransactionBroadcastSequence();
|
||||||
// test.testAccountLookupDeserialization();
|
// test.testAccountLookupDeserialization();
|
||||||
// test.testPrivateKeyManipulations();
|
// test.testPrivateKeyManipulations();
|
||||||
test.testPublicKeyManipulations();
|
// test.testPublicKeyManipulations();
|
||||||
// test.testGetAccountByName();
|
// test.testGetAccountByName();
|
||||||
// test.testGetRequiredFees();
|
// test.testGetRequiredFees();
|
||||||
// test.testRandomNumberGeneration();
|
// test.testRandomNumberGeneration();
|
||||||
|
@ -61,5 +61,6 @@ public class Main {
|
||||||
// test.testingInvoiceGeneration();
|
// test.testingInvoiceGeneration();
|
||||||
// test.testCompression();
|
// test.testCompression();
|
||||||
// test.testCreateBinFile();
|
// test.testCreateBinFile();
|
||||||
|
test.testAccountUpdateOperationSerialization();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -743,4 +743,21 @@ public class Test {
|
||||||
byte[] fileOutput = FileBin.getBytesFromBrainKey(Main.BRAIN_KEY, "123456","bithon-83");
|
byte[] fileOutput = FileBin.getBytesFromBrainKey(Main.BRAIN_KEY, "123456","bithon-83");
|
||||||
System.out.println("fileOutput " + Arrays.toString(fileOutput));
|
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<String, Integer> 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
||||||
private ECKey privateKey;
|
private ECKey privateKey;
|
||||||
private BlockData blockData;
|
private BlockData blockData;
|
||||||
private List<BaseOperation> operations;
|
private List<BaseOperation> operations;
|
||||||
private List<Extension> extensions;
|
private List<Extensions> extensions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transaction constructor.
|
* Transaction constructor.
|
||||||
|
@ -50,7 +50,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
||||||
this.privateKey = DumpedPrivateKey.fromBase58(null, wif).getKey();
|
this.privateKey = DumpedPrivateKey.fromBase58(null, wif).getKey();
|
||||||
this.blockData = block_data;
|
this.blockData = block_data;
|
||||||
this.operations = operation_list;
|
this.operations = operation_list;
|
||||||
this.extensions = new ArrayList<Extension>();
|
this.extensions = new ArrayList<Extensions>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +63,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
this.blockData = blockData;
|
this.blockData = blockData;
|
||||||
this.operations = operationList;
|
this.operations = operationList;
|
||||||
this.extensions = new ArrayList<Extension>();
|
this.extensions = new ArrayList<Extensions>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ECKey getPrivateKey(){
|
public ECKey getPrivateKey(){
|
||||||
|
@ -143,8 +143,8 @@ public class Transaction implements ByteSerializable, JsonSerializable {
|
||||||
//Adding the number of extensions
|
//Adding the number of extensions
|
||||||
byteArray.add((byte) this.extensions.size());
|
byteArray.add((byte) this.extensions.size());
|
||||||
|
|
||||||
for(Extension extension : extensions){
|
for(Extensions extensions : this.extensions){
|
||||||
//TODO: Implement the extension serialization
|
//TODO: Implement the extensions serialization
|
||||||
}
|
}
|
||||||
// Adding a last zero byte to match the result obtained by the python-graphenelib code
|
// 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
|
// I'm not exactly sure what's the meaning of this last zero byte, but for now I'll just
|
||||||
|
|
|
@ -44,11 +44,6 @@ public class TransferOperation extends BaseOperation {
|
||||||
this.fee = newFee;
|
this.fee = newFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte getId() {
|
|
||||||
return (byte) this.type.ordinal();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserAccount getFrom(){
|
public UserAccount getFrom(){
|
||||||
return this.from;
|
return this.from;
|
||||||
}
|
}
|
||||||
|
@ -77,6 +72,7 @@ public class TransferOperation extends BaseOperation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toJsonString() {
|
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 gsonBuilder = new GsonBuilder();
|
||||||
gsonBuilder.registerTypeAdapter(TransferOperation.class, new TransferSerializer());
|
gsonBuilder.registerTypeAdapter(TransferOperation.class, new TransferSerializer());
|
||||||
return gsonBuilder.create().toJson(this);
|
return gsonBuilder.create().toJson(this);
|
||||||
|
|
|
@ -46,6 +46,7 @@ public class TransferTransactionBuilder extends TransactionBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Add support for multiple transfer operations in a single transaction
|
||||||
public TransferTransactionBuilder addOperation(TransferOperation transferOperation){
|
public TransferTransactionBuilder addOperation(TransferOperation transferOperation){
|
||||||
if(operations == null){
|
if(operations == null){
|
||||||
operations = new ArrayList<BaseOperation>();
|
operations = new ArrayList<BaseOperation>();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.luminiasoft.bitshares;
|
package com.luminiasoft.bitshares;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Bytes;
|
||||||
import org.tukaani.xz.LZMA2Options;
|
import org.tukaani.xz.LZMA2Options;
|
||||||
import org.tukaani.xz.LZMAInputStream;
|
import org.tukaani.xz.LZMAInputStream;
|
||||||
import org.tukaani.xz.LZMAOutputStream;
|
import org.tukaani.xz.LZMAOutputStream;
|
||||||
|
@ -7,6 +8,7 @@ import org.tukaani.xz.LZMAOutputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.tukaani.xz.XZOutputStream;
|
import org.tukaani.xz.XZOutputStream;
|
||||||
|
@ -99,4 +101,33 @@ public class Util {
|
||||||
}
|
}
|
||||||
return null;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue