diff --git a/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java b/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java index c716e1c..447b3d0 100644 --- a/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java +++ b/src/main/java/com/luminiasoft/bitshares/AccountUpdateOperation.java @@ -6,8 +6,6 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.sun.istack.internal.NotNull; -import com.sun.istack.internal.Nullable; /** * Class used to encapsulate operations related to the account_update_operation. diff --git a/src/main/java/com/luminiasoft/bitshares/FileBin.java b/src/main/java/com/luminiasoft/bitshares/FileBin.java index d5fca7a..85310f9 100644 --- a/src/main/java/com/luminiasoft/bitshares/FileBin.java +++ b/src/main/java/com/luminiasoft/bitshares/FileBin.java @@ -38,13 +38,13 @@ public abstract class FileBin { public static String getBrainkeyFromByte(byte[] input, String password) { try { byte[] publicKey = new byte[33]; - byte[] rawDataEncripted = new byte[input.length-33]; + byte[] rawDataEncripted = new byte[input.length - 33]; System.arraycopy(input, 0, publicKey, 0, publicKey.length); System.arraycopy(input, 33, rawDataEncripted, 0, rawDataEncripted.length); MessageDigest md = MessageDigest.getInstance("SHA-256"); - + ECKey randomECKey = ECKey.fromPublicOnly(publicKey); byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(password.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded(); MessageDigest md1 = MessageDigest.getInstance("SHA-512"); @@ -64,7 +64,7 @@ public abstract class FileBin { } else { wallet = wallet.get("wallet").getAsJsonObject(); } - + byte[] encKey_enc = new BigInteger(wallet.get("encryption_key").getAsString(), 16).toByteArray(); byte[] temp = new byte[encKey_enc.length - (encKey_enc[0] == 0 ? 1 : 0)]; System.arraycopy(encKey_enc, (encKey_enc[0] == 0 ? 1 : 0), temp, 0, temp.length); @@ -73,8 +73,8 @@ public abstract class FileBin { System.arraycopy(encKey, 0, temp, 0, temp.length); byte[] encBrain = new BigInteger(wallet.get("encrypted_brainkey").getAsString(), 16).toByteArray(); - while(encBrain[0] == 0){ - byte[]temp2 = new byte[encBrain.length-1]; + while (encBrain[0] == 0) { + byte[] temp2 = new byte[encBrain.length - 1]; System.arraycopy(encBrain, 1, temp2, 0, temp2.length); encBrain = temp2; } diff --git a/src/main/java/com/luminiasoft/bitshares/Main.java b/src/main/java/com/luminiasoft/bitshares/Main.java index dff87d5..11784a4 100644 --- a/src/main/java/com/luminiasoft/bitshares/Main.java +++ b/src/main/java/com/luminiasoft/bitshares/Main.java @@ -50,14 +50,14 @@ public class Main { // test.testGetDynamicParams(); // test.testGetRequiredFeesSerialization(); // test.testRequiredFeesResponse(); -// test.testTransactionBroadcastSequence(); + test.testTransactionBroadcastSequence(); // test.testAccountLookupDeserialization(); // test.testPrivateKeyManipulations(); // test.testPublicKeyManipulations(); // test.testGetAccountByName(); // test.testGetRequiredFees(); // test.testRandomNumberGeneration(); - test.testBrainKeyOperations(false); + //test.testBrainKeyOperations(false); // test.testBip39Opertion(); // test.testAccountNamebyAddress(); // test.testAccountNameById(); @@ -68,5 +68,6 @@ public class Main { // test.testAccountUpdateOperationBroadcast(); // test.testCreateBinFile(); // test.testImportBinFile(); + //test.testLookupAccounts(); } } diff --git a/src/main/java/com/luminiasoft/bitshares/Memo.java b/src/main/java/com/luminiasoft/bitshares/Memo.java index b74ef52..0dd6982 100644 --- a/src/main/java/com/luminiasoft/bitshares/Memo.java +++ b/src/main/java/com/luminiasoft/bitshares/Memo.java @@ -1,57 +1,59 @@ package com.luminiasoft.bitshares; +import com.google.common.primitives.Bytes; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.luminiasoft.bitshares.crypto.SecureRandomStrengthener; import com.luminiasoft.bitshares.interfaces.ByteSerializable; +import com.luminiasoft.bitshares.interfaces.JsonSerializable; +import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import org.bitcoinj.core.Base58; import org.bitcoinj.core.ECKey; /** * Created by nelson on 11/9/16. */ -public class Memo implements ByteSerializable { +public class Memo implements ByteSerializable, JsonSerializable { + public static final String KEY_FROM = "from"; + public static final String KEY_TO = "to"; + public static final String KEY_NONCE = "nonce"; + public static final String KEY_MESSAGE = "message"; + //TODO: Give this class a proper implementation - private byte[] from; - private byte[] to; + private PublicKey from; + private PublicKey to; private byte[] nonce = new byte[8]; private byte[] message; - + @Override public byte[] toBytes() { - if ((this.from == null) || (this.to == null) || (this.nonce == null) ||(this.message == null)){ - return new byte[] { (byte) 0 }; + if ((this.from == null) || (this.to == null) || (this.nonce == null) || (this.message == null)) { + return new byte[]{(byte) 0}; } - - byte[] result = new byte[this.from.length+this.to.length+this.nonce.length+this.message.length]; - System.arraycopy(this.from, 0, result, 0, this.from.length); - System.arraycopy(this.to, 0, result, this.from.length, this.to.length); - System.arraycopy(this.nonce, 0, result, this.from.length+this.to.length, this.nonce.length); - System.arraycopy(this.message, 0, result, this.from.length+this.to.length+this.nonce.length, this.message.length); - - return result; + return Bytes.concat(this.from.toBytes(), this.to.toBytes(), this.nonce, this.message); } - - public Memo(){ + + public Memo() { this.from = null; - this.nonce = null; this.to = null; this.message = null; } - - public void encodeMessage(byte[] private_key, byte[] public_key, byte[] msg){ - this.encodeMessage(private_key,public_key,msg,0); + + public void encodeMessage(ECKey fromKey, ECKey toKey, byte[] msg) { + this.encodeMessage(fromKey, toKey, msg, 0); } - - public void encodeMessage(byte[] private_key, byte[] public_key, byte[] msg, long custom_nonce){ + + public void encodeMessage(ECKey fromKey, ECKey toKey, byte[] msg, long custom_nonce) { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); - ECKey privateECKey = ECKey.fromPrivate(md.digest(private_key)); - this.from = privateECKey.getPubKey(); - this.to = public_key; + this.from = new PublicKey(fromKey); + this.to = new PublicKey(toKey); - if (custom_nonce == 0){ + if (custom_nonce == 0) { SecureRandomStrengthener randomStrengthener = SecureRandomStrengthener.getInstance(); //randomStrengthener.addEntropySource(new AndroidRandomSource()); SecureRandom secureRandom = randomStrengthener.generateAndSeedRandomNumberGenerator(); @@ -59,24 +61,22 @@ public class Memo implements ByteSerializable { long time = System.currentTimeMillis(); - for (int i = 7;i >=1; i--){ - this.nonce[i] = (byte)(time&0xff); - time = time/0x100; + for (int i = 7; i >= 1; i--) { + this.nonce[i] = (byte) (time & 0xff); + time = time / 0x100; } } else { - for (int i = 7;i >=0; i--){ - this.nonce[i] = (byte)(custom_nonce&0xff); - custom_nonce = custom_nonce/0x100; + for (int i = 7; i >= 0; i--) { + this.nonce[i] = (byte) (custom_nonce & 0xff); + custom_nonce = custom_nonce / 0x100; } } - - byte[] secret = privateECKey.getPubKeyPoint().multiply(ECKey.fromPublicOnly(md.digest(public_key)).getPrivKey()).normalize().getXCoord().getEncoded(); + byte[] secret = fromKey.getPubKeyPoint().multiply(toKey.getPrivKey()).normalize().getXCoord().getEncoded(); byte[] finalKey = new byte[secret.length + this.nonce.length]; System.arraycopy(secret, 0, finalKey, 0, secret.length); System.arraycopy(this.nonce, 0, finalKey, secret.length, this.nonce.length); - - + byte[] sha256Msg = md.digest(msg); byte[] serialChecksum = new byte[4]; System.arraycopy(sha256Msg, 0, serialChecksum, 0, 4); @@ -85,30 +85,45 @@ public class Memo implements ByteSerializable { System.arraycopy(msg, 0, msgFinal, serialChecksum.length, msg.length); this.message = Util.encryptAES(msgFinal, finalKey); - } catch (NoSuchAlgorithmException ex){ - + } catch (NoSuchAlgorithmException ex) { + } } - - public void decodeMessage(byte[] private_key, byte[] public_key, byte[] msg, byte[] nonce){ - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - ECKey privateECKey = ECKey.fromPrivate(md.digest(private_key)); - this.to = privateECKey.getPubKey(); - this.from = public_key; - this.nonce = nonce; - - byte[] secret = privateECKey.getPubKeyPoint().multiply(ECKey.fromPublicOnly(md.digest(public_key)).getPrivKey()).normalize().getXCoord().getEncoded(); - byte[] finalKey = new byte[secret.length + this.nonce.length]; - System.arraycopy(secret, 0, finalKey, 0, secret.length); - System.arraycopy(this.nonce, 0, finalKey, secret.length, this.nonce.length); - - byte[] msgFinal = Util.decryptAES(msg, finalKey); - byte[] decodedMsg = new byte[msgFinal.length-4]; - System.arraycopy(msgFinal, 4, decodedMsg, 0, decodedMsg.length); - this.message = decodedMsg; - } catch (NoSuchAlgorithmException ex){ - - } + + public void decodeMessage(ECKey toKey, ECKey fromKey, byte[] msg, byte[] nonce) { + this.to = new PublicKey(toKey); + this.from = new PublicKey(fromKey); + this.nonce = nonce; + + byte[] secret = toKey.getPubKeyPoint().multiply(fromKey.getPrivKey()).normalize().getXCoord().getEncoded(); + byte[] finalKey = new byte[secret.length + this.nonce.length]; + System.arraycopy(secret, 0, finalKey, 0, secret.length); + System.arraycopy(this.nonce, 0, finalKey, secret.length, this.nonce.length); + + byte[] msgFinal = Util.decryptAES(msg, finalKey); + byte[] decodedMsg = new byte[msgFinal.length - 4]; + //TODO verify checksum for integrity + System.arraycopy(msgFinal, 4, decodedMsg, 0, decodedMsg.length); + this.message = decodedMsg; } + + @Override + public String toJsonString() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public JsonElement toJsonObject() { + if ((this.from == null) || (this.to == null) || (this.nonce == null) || (this.message == null)) { + return null; + } + JsonObject memoObject = new JsonObject(); + memoObject.addProperty(KEY_FROM, new Address(this.from.getKey()).toString()); + memoObject.addProperty(KEY_TO, new Address(this.to.getKey()).toString()); + //memoObject.addProperty(KEY_NONCE, new BigInteger(1,this.nonce).toString(10)); + memoObject.addProperty(KEY_NONCE, new BigInteger(1,this.nonce).toString(10)); + memoObject.addProperty(KEY_MESSAGE, new BigInteger(1,this.message).toString(16)); + return memoObject; + } + } diff --git a/src/main/java/com/luminiasoft/bitshares/RPC.java b/src/main/java/com/luminiasoft/bitshares/RPC.java index feb7d8e..f7db64b 100644 --- a/src/main/java/com/luminiasoft/bitshares/RPC.java +++ b/src/main/java/com/luminiasoft/bitshares/RPC.java @@ -15,4 +15,5 @@ public class RPC { public static final String CALL_GET_ACCOUNTS = "get_accounts"; public static final String CALL_GET_KEY_REFERENCES = "get_key_references"; public static final String CALL_GET_RELATIVE_ACCOUNT_HISTORY = "get_relative_account_history"; + public static final String CALL_LOOKUP_ACCOUNTS = "lookup_accounts"; } diff --git a/src/main/java/com/luminiasoft/bitshares/Test.java b/src/main/java/com/luminiasoft/bitshares/Test.java index 193df2f..1f9b352 100644 --- a/src/main/java/com/luminiasoft/bitshares/Test.java +++ b/src/main/java/com/luminiasoft/bitshares/Test.java @@ -3,6 +3,7 @@ package com.luminiasoft.bitshares; import com.google.common.primitives.UnsignedLong; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.google.gson.reflect.TypeToken; import com.luminiasoft.bitshares.errors.MalformedAddressException; import com.luminiasoft.bitshares.errors.MalformedTransactionException; @@ -45,7 +46,10 @@ public class Test { if (response.result.getClass() == AccountProperties.class) { AccountProperties accountProperties = (AccountProperties) response.result; System.out.println("Got account properties"); + System.out.println("account: " + accountProperties.toString()); System.out.println("id: " + accountProperties.id); + + } else if (response.result.getClass() == ArrayList.class) { List list = (List) response.result; if (list.size() > 0) { @@ -93,6 +97,8 @@ public class Test { } else { System.out.println("Got empty list!"); } + } else if (response.result.getClass() == JsonArray.class) { + System.out.println("Json array : " + ((JsonArray)response.result)); } else { System.out.println("Got other: " + response.result.getClass()); } @@ -289,10 +295,12 @@ public class Test { Transaction transaction = new TransferTransactionBuilder() .setSource(new UserAccount("1.2.138632")) .setDestination(new UserAccount("1.2.129848")) - .setAmount(new AssetAmount(UnsignedLong.valueOf(100), new Asset("1.3.120"))) + .setAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.120"))) .setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0"))) .setBlockData(new BlockData(43408, 1430521623, 1479231969)) - .setPrivateKey(DumpedPrivateKey.fromBase58(null, Main.BILTHON_5_BRAIN_KEY).getKey()) + //.setPrivateKey(DumpedPrivateKey.fromBase58(null, Main.BILTHON_5_BRAIN_KEY).getKey()) + .setPrivateKey(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPrivateKey()) + //.setMemo("prueba", new BrainKey(Main.BILTHON_7_BRAIN_KEY, 0).getPrivateKey()) .build(); ArrayList transactionList = new ArrayList<>(); @@ -564,9 +572,10 @@ public class Test { } public void testImportBinFile() { - byte inputBytes[] = new byte[] {(byte)2, (byte)175, (byte)24, (byte)227, (byte)182, (byte)11, (byte)113, (byte)151, (byte)112, (byte)157, (byte)137, (byte)157, (byte)244, (byte)237, (byte)228, (byte)92, (byte)34, (byte)138, (byte)171, (byte)248, (byte)24, (byte)161, (byte)171, (byte)75, (byte)2, (byte)183, (byte)47, (byte)213, (byte)50, (byte)109, (byte)220, (byte)6, (byte)124, (byte)108, (byte)32, (byte)164, (byte)204, (byte)234, (byte)10, (byte)12, (byte)154, (byte)225, (byte)11, (byte)178, (byte)238, (byte)9, (byte)122, (byte)244, (byte)175, (byte)185, (byte)143, (byte)27, (byte)134, (byte)192, (byte)37, (byte)239, (byte)148, (byte)253, (byte)124, (byte)68, (byte)6, (byte)211, (byte)20, (byte)224, (byte)50, (byte)31, (byte)208, (byte)87, (byte)115, (byte)115, (byte)11, (byte)81, (byte)182, (byte)223, (byte)230, (byte)102, (byte)230, (byte)245, (byte)182, (byte)77, (byte)157, (byte)182, (byte)79, (byte)247, (byte)134, (byte)178, (byte)87, (byte)93, (byte)146, (byte)89, (byte)167, (byte)191, (byte)34, (byte)17, (byte)117, (byte)173, (byte)59, (byte)142, (byte)54, (byte)120, (byte)237, (byte)124, (byte)217, (byte)252, (byte)112, (byte)97, (byte)153, (byte)124, (byte)144, (byte)80, (byte)33, (byte)130, (byte)15, (byte)18, (byte)157, (byte)98, (byte)130, (byte)80, (byte)206, (byte)27, (byte)8, (byte)142, (byte)245, (byte)22, (byte)244, (byte)219, (byte)38, (byte)228, (byte)173, (byte)147, (byte)42, (byte)100, (byte)99, (byte)108, (byte)146, (byte)110, (byte)100, (byte)215, (byte)183, (byte)20, (byte)112, (byte)93, (byte)195, (byte)12, (byte)174, (byte)130, (byte)35, (byte)71, (byte)172, (byte)237, (byte)112, (byte)197, (byte)250, (byte)67, (byte)36, (byte)185, (byte)117, (byte)211, (byte)147, (byte)21, (byte)251, (byte)214, (byte)178, (byte)152, (byte)25, (byte)107, (byte)206, (byte)184, (byte)113, (byte)67, (byte)169, (byte)55, (byte)95, (byte)249, (byte)193, (byte)215, (byte)20, (byte)124, (byte)62, (byte)179, (byte)125, (byte)2, (byte)96, (byte)46, (byte)137, (byte)133, (byte)46, (byte)37, (byte)138, (byte)19, (byte)215, (byte)2, (byte)189, (byte)91, (byte)61, (byte)119, (byte)150, (byte)6, (byte)188, (byte)220, (byte)232, (byte)12, (byte)108, (byte)128, (byte)92, (byte)172, (byte)119, (byte)138, (byte)215, (byte)90, (byte)8, (byte)56, (byte)126, (byte)145, (byte)133, (byte)193, (byte)47, (byte)147, (byte)106, (byte)219, (byte)58, (byte)227, (byte)20, (byte)60, (byte)147, (byte)38, (byte)218, (byte)17, (byte)130, (byte)196, (byte)134, (byte)105, (byte)94, (byte)235, (byte)26, (byte)245, (byte)119, (byte)153, (byte)11, (byte)29, (byte)33, (byte)230, (byte)151, (byte)149, (byte)63, (byte)91, (byte)170, (byte)75, (byte)43, (byte)223, (byte)192, (byte)104, (byte)161, (byte)58, (byte)135, (byte)226, (byte)175, (byte)171, (byte)202, (byte)113, (byte)142, (byte)40, (byte)139, (byte)240, (byte)10, (byte)54, (byte)213, (byte)55, (byte)235, (byte)175, (byte)211, (byte)193, (byte)151, (byte)43, (byte)233, (byte)81, (byte)250, (byte)245, (byte)120, (byte)211, (byte)107, (byte)73, (byte)75, (byte)74, (byte)98, (byte)10, (byte)208, (byte)68, (byte)185, (byte)183, (byte)251, (byte)193, (byte)65, (byte)125, (byte)65, (byte)52, (byte)154, (byte)115, (byte)118, (byte)217, (byte)254, (byte)140, (byte)116, (byte)124, (byte)158, (byte)70, (byte)94, (byte)28, (byte)132, (byte)231, (byte)142, (byte)209, (byte)163, (byte)182, (byte)227, (byte)129, (byte)243, (byte)130, (byte)28, (byte)238, (byte)35, (byte)235, (byte)120, (byte)199, (byte)26, (byte)209, (byte)58, (byte)181, (byte)124, (byte)44, (byte)38, (byte)132, (byte)54, (byte)168, (byte)31, (byte)150, (byte)191, (byte)140, (byte)101, (byte)141, (byte)104, (byte)74, (byte)29, (byte)76, (byte)254, (byte)67, (byte)43, (byte)123, (byte)67, (byte)208, (byte)132, (byte)61, (byte)36, (byte)167, (byte)195, (byte)231, (byte)234, (byte)136, (byte)55, (byte)97, (byte)205, (byte)242, (byte)182, (byte)237, (byte)179, (byte)13, (byte)24, (byte)249, (byte)53, (byte)151, (byte)66, (byte)252, (byte)254, (byte)173, (byte)91, (byte)52, (byte)70, (byte)239, (byte)235, (byte)94, (byte)18, (byte)115, (byte)143, (byte)134, (byte)206, (byte)244, (byte)77, (byte)247, (byte)201, (byte)61, (byte)115, (byte)78, (byte)186, (byte)199, (byte)89, (byte)144, (byte)69, (byte)231, (byte)174, (byte)2, (byte)167, (byte)157, (byte)148, (byte)88, (byte)150, (byte)171, (byte)50, (byte)82, (byte)230, (byte)211, (byte)14, (byte)55, (byte)165, (byte)103, (byte)67, (byte)172, (byte)148, (byte)252, (byte)10, (byte)104, (byte)24, (byte)179, (byte)152, (byte)156, (byte)169, (byte)228, (byte)123, (byte)205, (byte)247, (byte)10, (byte)127, (byte)106, (byte)100, (byte)10, (byte)187, (byte)81, (byte)0, (byte)55, (byte)177, (byte)60, (byte)139, (byte)41, (byte)62, (byte)163, (byte)83, (byte)242, (byte)1, (byte)122, (byte)247, (byte)181, (byte)102, (byte)218, (byte)205, (byte)70, (byte)235, (byte)147, (byte)195, (byte)107, (byte)248, (byte)139, (byte)169, (byte)203, (byte)174, (byte)22, (byte)126, (byte)65, (byte)123, (byte)14, (byte)33, (byte)131, (byte)49, (byte)6, (byte)187, (byte)156, (byte)50, (byte)92, (byte)145, (byte)74, (byte)90, (byte)132, (byte)151, (byte)105, (byte)187, (byte)195, (byte)56, (byte)45, (byte)134, (byte)204, (byte)7, (byte)130, (byte)153, (byte)209, (byte)87, (byte)231, (byte)78, (byte)90, (byte)168, (byte)93, (byte)200, (byte)149, (byte)204, (byte)128, (byte)85, (byte)17, (byte)17, (byte)219, (byte)161, (byte)167, (byte)73, (byte)218, (byte)116, (byte)233, (byte)202, (byte)19, (byte)110, (byte)95, (byte)115, (byte)233, (byte)137, (byte)85, (byte)112, (byte)70, (byte)226, (byte)217, (byte)126, (byte)70, (byte)214, (byte)47, (byte)133, (byte)129, (byte)78, (byte)127, (byte)81, (byte)192, (byte)48, (byte)91, (byte)224, (byte)124, (byte)13, (byte)176, (byte)131, (byte)53, (byte)192, (byte)92, (byte)113, (byte)235, (byte)86, (byte)38, (byte)178, (byte)133, (byte)204, (byte)110, (byte)195, (byte)230, (byte)140, (byte)213, (byte)208, (byte)188, (byte)185, (byte)37, (byte)103, (byte)177, (byte)181, (byte)120, (byte)78, (byte)192, (byte)30, (byte)224, (byte)250, (byte)2, (byte)66, (byte)76, (byte)162, (byte)87, (byte)8, (byte)131, (byte)54, (byte)247, (byte)91, (byte)9, (byte)236, (byte)18, (byte)53, (byte)11, (byte)141, (byte)144, (byte)193, (byte)139, (byte)168, (byte)170, (byte)223, (byte)190, (byte)90, (byte)23, (byte)29, (byte)177, (byte)79, (byte)38, (byte)232, (byte)148, (byte)80, (byte)211, (byte)207, (byte)201, (byte)129, (byte)2, (byte)228, (byte)86, (byte)144, (byte)32, (byte)27, (byte)235, (byte)105, (byte)136, (byte)217, (byte)195, (byte)234, (byte)243, (byte)198, (byte)87, (byte)186, (byte)31, (byte)21, (byte)144, (byte)200, (byte)27, (byte)34, (byte)82, (byte)220, (byte)37, (byte)67, (byte)44, (byte)140, (byte)233, (byte)144, (byte)218, (byte)185, (byte)46, (byte)151, (byte)96, (byte)91}; - //BigInteger b = new BigInteger(new String(inputBytes),16); + byte inputBytes[] = new byte[]{(byte) 2, (byte) 175, (byte) 24, (byte) 227, (byte) 182, (byte) 11, (byte) 113, (byte) 151, (byte) 112, (byte) 157, (byte) 137, (byte) 157, (byte) 244, (byte) 237, (byte) 228, (byte) 92, (byte) 34, (byte) 138, (byte) 171, (byte) 248, (byte) 24, (byte) 161, (byte) 171, (byte) 75, (byte) 2, (byte) 183, (byte) 47, (byte) 213, (byte) 50, (byte) 109, (byte) 220, (byte) 6, (byte) 124, (byte) 108, (byte) 32, (byte) 164, (byte) 204, (byte) 234, (byte) 10, (byte) 12, (byte) 154, (byte) 225, (byte) 11, (byte) 178, (byte) 238, (byte) 9, (byte) 122, (byte) 244, (byte) 175, (byte) 185, (byte) 143, (byte) 27, (byte) 134, (byte) 192, (byte) 37, (byte) 239, (byte) 148, (byte) 253, (byte) 124, (byte) 68, (byte) 6, (byte) 211, (byte) 20, (byte) 224, (byte) 50, (byte) 31, (byte) 208, (byte) 87, (byte) 115, (byte) 115, (byte) 11, (byte) 81, (byte) 182, (byte) 223, (byte) 230, (byte) 102, (byte) 230, (byte) 245, (byte) 182, (byte) 77, (byte) 157, (byte) 182, (byte) 79, (byte) 247, (byte) 134, (byte) 178, (byte) 87, (byte) 93, (byte) 146, (byte) 89, (byte) 167, (byte) 191, (byte) 34, (byte) 17, (byte) 117, (byte) 173, (byte) 59, (byte) 142, (byte) 54, (byte) 120, (byte) 237, (byte) 124, (byte) 217, (byte) 252, (byte) 112, (byte) 97, (byte) 153, (byte) 124, (byte) 144, (byte) 80, (byte) 33, (byte) 130, (byte) 15, (byte) 18, (byte) 157, (byte) 98, (byte) 130, (byte) 80, (byte) 206, (byte) 27, (byte) 8, (byte) 142, (byte) 245, (byte) 22, (byte) 244, (byte) 219, (byte) 38, (byte) 228, (byte) 173, (byte) 147, (byte) 42, (byte) 100, (byte) 99, (byte) 108, (byte) 146, (byte) 110, (byte) 100, (byte) 215, (byte) 183, (byte) 20, (byte) 112, (byte) 93, (byte) 195, (byte) 12, (byte) 174, (byte) 130, (byte) 35, (byte) 71, (byte) 172, (byte) 237, (byte) 112, (byte) 197, (byte) 250, (byte) 67, (byte) 36, (byte) 185, (byte) 117, (byte) 211, (byte) 147, (byte) 21, (byte) 251, (byte) 214, (byte) 178, (byte) 152, (byte) 25, (byte) 107, (byte) 206, (byte) 184, (byte) 113, (byte) 67, (byte) 169, (byte) 55, (byte) 95, (byte) 249, (byte) 193, (byte) 215, (byte) 20, (byte) 124, (byte) 62, (byte) 179, (byte) 125, (byte) 2, (byte) 96, (byte) 46, (byte) 137, (byte) 133, (byte) 46, (byte) 37, (byte) 138, (byte) 19, (byte) 215, (byte) 2, (byte) 189, (byte) 91, (byte) 61, (byte) 119, (byte) 150, (byte) 6, (byte) 188, (byte) 220, (byte) 232, (byte) 12, (byte) 108, (byte) 128, (byte) 92, (byte) 172, (byte) 119, (byte) 138, (byte) 215, (byte) 90, (byte) 8, (byte) 56, (byte) 126, (byte) 145, (byte) 133, (byte) 193, (byte) 47, (byte) 147, (byte) 106, (byte) 219, (byte) 58, (byte) 227, (byte) 20, (byte) 60, (byte) 147, (byte) 38, (byte) 218, (byte) 17, (byte) 130, (byte) 196, (byte) 134, (byte) 105, (byte) 94, (byte) 235, (byte) 26, (byte) 245, (byte) 119, (byte) 153, (byte) 11, (byte) 29, (byte) 33, (byte) 230, (byte) 151, (byte) 149, (byte) 63, (byte) 91, (byte) 170, (byte) 75, (byte) 43, (byte) 223, (byte) 192, (byte) 104, (byte) 161, (byte) 58, (byte) 135, (byte) 226, (byte) 175, (byte) 171, (byte) 202, (byte) 113, (byte) 142, (byte) 40, (byte) 139, (byte) 240, (byte) 10, (byte) 54, (byte) 213, (byte) 55, (byte) 235, (byte) 175, (byte) 211, (byte) 193, (byte) 151, (byte) 43, (byte) 233, (byte) 81, (byte) 250, (byte) 245, (byte) 120, (byte) 211, (byte) 107, (byte) 73, (byte) 75, (byte) 74, (byte) 98, (byte) 10, (byte) 208, (byte) 68, (byte) 185, (byte) 183, (byte) 251, (byte) 193, (byte) 65, (byte) 125, (byte) 65, (byte) 52, (byte) 154, (byte) 115, (byte) 118, (byte) 217, (byte) 254, (byte) 140, (byte) 116, (byte) 124, (byte) 158, (byte) 70, (byte) 94, (byte) 28, (byte) 132, (byte) 231, (byte) 142, (byte) 209, (byte) 163, (byte) 182, (byte) 227, (byte) 129, (byte) 243, (byte) 130, (byte) 28, (byte) 238, (byte) 35, (byte) 235, (byte) 120, (byte) 199, (byte) 26, (byte) 209, (byte) 58, (byte) 181, (byte) 124, (byte) 44, (byte) 38, (byte) 132, (byte) 54, (byte) 168, (byte) 31, (byte) 150, (byte) 191, (byte) 140, (byte) 101, (byte) 141, (byte) 104, (byte) 74, (byte) 29, (byte) 76, (byte) 254, (byte) 67, (byte) 43, (byte) 123, (byte) 67, (byte) 208, (byte) 132, (byte) 61, (byte) 36, (byte) 167, (byte) 195, (byte) 231, (byte) 234, (byte) 136, (byte) 55, (byte) 97, (byte) 205, (byte) 242, (byte) 182, (byte) 237, (byte) 179, (byte) 13, (byte) 24, (byte) 249, (byte) 53, (byte) 151, (byte) 66, (byte) 252, (byte) 254, (byte) 173, (byte) 91, (byte) 52, (byte) 70, (byte) 239, (byte) 235, (byte) 94, (byte) 18, (byte) 115, (byte) 143, (byte) 134, (byte) 206, (byte) 244, (byte) 77, (byte) 247, (byte) 201, (byte) 61, (byte) 115, (byte) 78, (byte) 186, (byte) 199, (byte) 89, (byte) 144, (byte) 69, (byte) 231, (byte) 174, (byte) 2, (byte) 167, (byte) 157, (byte) 148, (byte) 88, (byte) 150, (byte) 171, (byte) 50, (byte) 82, (byte) 230, (byte) 211, (byte) 14, (byte) 55, (byte) 165, (byte) 103, (byte) 67, (byte) 172, (byte) 148, (byte) 252, (byte) 10, (byte) 104, (byte) 24, (byte) 179, (byte) 152, (byte) 156, (byte) 169, (byte) 228, (byte) 123, (byte) 205, (byte) 247, (byte) 10, (byte) 127, (byte) 106, (byte) 100, (byte) 10, (byte) 187, (byte) 81, (byte) 0, (byte) 55, (byte) 177, (byte) 60, (byte) 139, (byte) 41, (byte) 62, (byte) 163, (byte) 83, (byte) 242, (byte) 1, (byte) 122, (byte) 247, (byte) 181, (byte) 102, (byte) 218, (byte) 205, (byte) 70, (byte) 235, (byte) 147, (byte) 195, (byte) 107, (byte) 248, (byte) 139, (byte) 169, (byte) 203, (byte) 174, (byte) 22, (byte) 126, (byte) 65, (byte) 123, (byte) 14, (byte) 33, (byte) 131, (byte) 49, (byte) 6, (byte) 187, (byte) 156, (byte) 50, (byte) 92, (byte) 145, (byte) 74, (byte) 90, (byte) 132, (byte) 151, (byte) 105, (byte) 187, (byte) 195, (byte) 56, (byte) 45, (byte) 134, (byte) 204, (byte) 7, (byte) 130, (byte) 153, (byte) 209, (byte) 87, (byte) 231, (byte) 78, (byte) 90, (byte) 168, (byte) 93, (byte) 200, (byte) 149, (byte) 204, (byte) 128, (byte) 85, (byte) 17, (byte) 17, (byte) 219, (byte) 161, (byte) 167, (byte) 73, (byte) 218, (byte) 116, (byte) 233, (byte) 202, (byte) 19, (byte) 110, (byte) 95, (byte) 115, (byte) 233, (byte) 137, (byte) 85, (byte) 112, (byte) 70, (byte) 226, (byte) 217, (byte) 126, (byte) 70, (byte) 214, (byte) 47, (byte) 133, (byte) 129, (byte) 78, (byte) 127, (byte) 81, (byte) 192, (byte) 48, (byte) 91, (byte) 224, (byte) 124, (byte) 13, (byte) 176, (byte) 131, (byte) 53, (byte) 192, (byte) 92, (byte) 113, (byte) 235, (byte) 86, (byte) 38, (byte) 178, (byte) 133, (byte) 204, (byte) 110, (byte) 195, (byte) 230, (byte) 140, (byte) 213, (byte) 208, (byte) 188, (byte) 185, (byte) 37, (byte) 103, (byte) 177, (byte) 181, (byte) 120, (byte) 78, (byte) 192, (byte) 30, (byte) 224, (byte) 250, (byte) 2, (byte) 66, (byte) 76, (byte) 162, (byte) 87, (byte) 8, (byte) 131, (byte) 54, (byte) 247, (byte) 91, (byte) 9, (byte) 236, (byte) 18, (byte) 53, (byte) 11, (byte) 141, (byte) 144, (byte) 193, (byte) 139, (byte) 168, (byte) 170, (byte) 223, (byte) 190, (byte) 90, (byte) 23, (byte) 29, (byte) 177, (byte) 79, (byte) 38, (byte) 232, (byte) 148, (byte) 80, (byte) 211, (byte) 207, (byte) 201, (byte) 129, (byte) 2, (byte) 228, (byte) 86, (byte) 144, (byte) 32, (byte) 27, (byte) 235, (byte) 105, (byte) 136, (byte) 217, (byte) 195, (byte) 234, (byte) 243, (byte) 198, (byte) 87, (byte) 186, (byte) 31, (byte) 21, (byte) 144, (byte) 200, (byte) 27, (byte) 34, (byte) 82, (byte) 220, (byte) 37, (byte) 67, (byte) 44, (byte) 140, (byte) 233, (byte) 144, (byte) 218, (byte) 185, (byte) 46, (byte) 151, (byte) 96, (byte) 91}; + System.out.println(FileBin.getBrainkeyFromByte(inputBytes, "123456")); + } public void testAccountUpdateSerialization() { @@ -650,4 +659,40 @@ public class Test { System.out.println("WebSocketException. Msg: "+e.getMessage()); } } + + public void testLookupAccounts(){ + WitnessResponseListener listener = new WitnessResponseListener() { + @Override + public void onSuccess(WitnessResponse response) { + System.out.println("onSuccess"); + } + + @Override + public void onError(BaseResponse.Error error) { + System.out.println("onError"); + } + }; + + SSLContext context = null; + try { + context = NaiveSSLContext.getInstance("TLS"); + WebSocketFactory factory = new WebSocketFactory(); + + // Set the custom SSL context. + factory.setSSLContext(context); + + WebSocket mWebSocket = factory.createSocket(OPENLEDGER_WITNESS_URL); + + mWebSocket.addListener(new LookupAccounts("bilthon", listener)); + mWebSocket.connect(); + + } catch (NoSuchAlgorithmException e) { + System.out.println("NoSuchAlgorithmException. Msg: "+e.getMessage()); + } catch (WebSocketException e) { + System.out.println("WebSocketException. Msg: "+e.getMessage()); + } catch (IOException e) { + System.out.println("IOException. Msg: "+e.getMessage()); + } + } + } diff --git a/src/main/java/com/luminiasoft/bitshares/TransferOperation.java b/src/main/java/com/luminiasoft/bitshares/TransferOperation.java index 4f12f70..03655cd 100644 --- a/src/main/java/com/luminiasoft/bitshares/TransferOperation.java +++ b/src/main/java/com/luminiasoft/bitshares/TransferOperation.java @@ -4,6 +4,7 @@ import com.google.common.primitives.Bytes; import com.google.gson.*; import java.lang.reflect.Type; +import org.bitcoinj.core.ECKey; /** * Class used to encapsulate the TransferOperation operation related functionalities. @@ -15,6 +16,7 @@ public class TransferOperation extends BaseOperation { public static final String KEY_EXTENSIONS = "extensions"; public static final String KEY_FROM = "from"; public static final String KEY_TO = "to"; + public static final String KEY_MEMO = "memo"; private AssetAmount fee; private AssetAmount amount; @@ -86,6 +88,7 @@ public class TransferOperation extends BaseOperation { JsonObject jsonObject = new JsonObject(); jsonObject.add(KEY_FEE, fee.toJsonObject()); jsonObject.add(KEY_AMOUNT, amount.toJsonObject()); + //jsonObject.add(KEY_MEMO, memo.toJsonObject()); jsonObject.add(KEY_EXTENSIONS, new JsonArray()); jsonObject.addProperty(KEY_FROM, from.toJsonString()); jsonObject.addProperty(KEY_TO, to.toJsonString()); @@ -93,6 +96,10 @@ public class TransferOperation extends BaseOperation { return array; } + public void setMemo(ECKey fromKey, ECKey toKey, byte[] memo) { + this.memo.encodeMessage(fromKey, toKey, memo); + } + public static class TransferSerializer implements JsonSerializer { @Override diff --git a/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java b/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java index c3ada97..0e8ce7b 100644 --- a/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java +++ b/src/main/java/com/luminiasoft/bitshares/TransferTransactionBuilder.java @@ -15,6 +15,8 @@ public class TransferTransactionBuilder extends TransactionBuilder { private UserAccount destinationAccount; private AssetAmount transferAmount; private AssetAmount feeAmount; + private String memo; + private ECKey memoPublicKey; public TransferTransactionBuilder(){} @@ -51,6 +53,12 @@ public class TransferTransactionBuilder extends TransactionBuilder { this.feeAmount = amount; return this; } + + public TransferTransactionBuilder setMemo(String memo,ECKey publicKey){ + this.memo = memo; + this.memoPublicKey = publicKey; + return this; + } //TODO: Add support for multiple transfer operations in a single transaction public TransferTransactionBuilder addOperation(TransferOperation transferOperation){ @@ -84,6 +92,10 @@ public class TransferTransactionBuilder extends TransactionBuilder { }else{ transferOperation = new TransferOperation(sourceAccount, destinationAccount, transferAmount, feeAmount); } + if(memo != null){ + + transferOperation.setMemo(this.privateKey,this.memoPublicKey,memo.getBytes()); + } operations.add(transferOperation); } return new Transaction(privateKey, blockData, operations); diff --git a/src/main/java/com/luminiasoft/bitshares/UserAccount.java b/src/main/java/com/luminiasoft/bitshares/UserAccount.java index e25c261..8ed3743 100644 --- a/src/main/java/com/luminiasoft/bitshares/UserAccount.java +++ b/src/main/java/com/luminiasoft/bitshares/UserAccount.java @@ -1,6 +1,6 @@ package com.luminiasoft.bitshares; -import com.google.gson.JsonObject; +import com.google.gson.*; import com.luminiasoft.bitshares.interfaces.ByteSerializable; import com.luminiasoft.bitshares.interfaces.JsonSerializable; @@ -8,6 +8,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.IOException; +import java.lang.reflect.Type; /** * Class tha represents a graphene user account. @@ -17,15 +18,35 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso public static final String PROXY_TO_SELF = "1.2.5"; + private String accountName; + /** * Constructor that expects a user account in the string representation. * That is in the 1.2.x format. - * @param id: The string representing the account apiId. + * @param id: The string representing the user account. */ public UserAccount(String id) { super(id); } + /** + * Constructor that expects a user account withe the proper graphene object id and an account name. + * @param id: The string representing the user account. + * @param name: The name of this user account. + */ + public UserAccount(String id, String name){ + super(id); + this.accountName = name; + } + + /** + * Getter for the account name field. + * @return: The name of this account. + */ + public String getAccountName() { + return accountName; + } + @Override public byte[] toBytes() { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); @@ -52,4 +73,24 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso public String toString() { return this.toJsonString(); } + + /** + * Custom deserializer used to deserialize user accounts provided as response from the 'lookup_accounts' api call. + * This response contains serialized user accounts in the form [[{id1},{name1}][{id1},{name1}]]. + * + * For instance: + * [["bilthon-1","1.2.139205"],["bilthon-2","1.2.139207"],["bilthon-2016","1.2.139262"]] + * + * So this class will pick up this data and turn it into a UserAccount object. + */ + public static class UserAccountDeserializer implements JsonDeserializer { + + @Override + public UserAccount deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonArray array = json.getAsJsonArray(); + String name = array.get(0).getAsString(); + String id = array.get(1).getAsString(); + return new UserAccount(id, name); + } + } } diff --git a/src/main/java/com/luminiasoft/bitshares/Util.java b/src/main/java/com/luminiasoft/bitshares/Util.java index 1c67072..d6b45f7 100644 --- a/src/main/java/com/luminiasoft/bitshares/Util.java +++ b/src/main/java/com/luminiasoft/bitshares/Util.java @@ -1,6 +1,7 @@ package com.luminiasoft.bitshares; import org.tukaani.xz.FinishableOutputStream; +import com.google.common.primitives.Bytes; import org.tukaani.xz.LZMA2Options; import org.tukaani.xz.LZMAInputStream; import org.tukaani.xz.LZMAOutputStream; diff --git a/src/main/java/com/luminiasoft/bitshares/ws/LookupAccounts.java b/src/main/java/com/luminiasoft/bitshares/ws/LookupAccounts.java new file mode 100644 index 0000000..e6e44d7 --- /dev/null +++ b/src/main/java/com/luminiasoft/bitshares/ws/LookupAccounts.java @@ -0,0 +1,88 @@ +package com.luminiasoft.bitshares.ws; + +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.luminiasoft.bitshares.RPC; +import com.luminiasoft.bitshares.UserAccount; +import com.luminiasoft.bitshares.interfaces.WitnessResponseListener; +import com.luminiasoft.bitshares.models.ApiCall; +import com.luminiasoft.bitshares.models.BaseResponse; +import com.luminiasoft.bitshares.models.WitnessResponse; +import com.neovisionaries.ws.client.WebSocket; +import com.neovisionaries.ws.client.WebSocketAdapter; +import com.neovisionaries.ws.client.WebSocketException; +import com.neovisionaries.ws.client.WebSocketFrame; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Created by henry on 07/12/16. + */ +public class LookupAccounts extends WebSocketAdapter { + + public static final int DEFAULT_MAX = 1000; + private final String accountName; + private int maxAccounts = DEFAULT_MAX; + private final WitnessResponseListener mListener; + + public LookupAccounts(String accountName, WitnessResponseListener listener){ + this.accountName = accountName; + this.maxAccounts = DEFAULT_MAX; + this.mListener = listener; + } + + public LookupAccounts(String accountName, int maxAccounts, WitnessResponseListener listener){ + this.accountName = accountName; + this.maxAccounts = maxAccounts; + this.mListener = listener; + } + + @Override + public void onConnected(WebSocket websocket, Map> headers) throws Exception { + ArrayList accountParams = new ArrayList<>(); + accountParams.add(this.accountName); + accountParams.add(this.maxAccounts); + ApiCall getAccountByName = new ApiCall(0, RPC.CALL_LOOKUP_ACCOUNTS, accountParams, RPC.VERSION, 1); + websocket.sendText(getAccountByName.toJsonString()); + } + + @Override + public void onTextFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { + System.out.println("<<< "+frame.getPayloadText()); + String response = frame.getPayloadText(); + + Type LookupAccountsResponse = new TypeToken>>(){}.getType(); + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountDeserializer()); + WitnessResponse> witnessResponse = builder.create().fromJson(response, LookupAccountsResponse); + if(witnessResponse.error != null){ + this.mListener.onError(witnessResponse.error); + }else{ + this.mListener.onSuccess(witnessResponse); + } + + websocket.disconnect(); + } + + @Override + public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception { + if(frame.isTextFrame()) + System.out.println(">>> "+frame.getPayloadText()); + } + + @Override + public void onError(WebSocket websocket, WebSocketException cause) throws Exception { + mListener.onError(new BaseResponse.Error(cause.getMessage())); + websocket.disconnect(); + } + + @Override + public void handleCallbackError(WebSocket websocket, Throwable cause) throws Exception { + mListener.onError(new BaseResponse.Error(cause.getMessage())); + websocket.disconnect(); + } +} \ No newline at end of file