diff --git a/app/src/main/java/de/bitsharesmunich/graphenej/Main.java b/app/src/main/java/de/bitsharesmunich/graphenej/Main.java index 86014c8..65dc19e 100644 --- a/app/src/main/java/de/bitsharesmunich/graphenej/Main.java +++ b/app/src/main/java/de/bitsharesmunich/graphenej/Main.java @@ -21,7 +21,13 @@ public class Main { public static final String BILTHON_25_PASSWORD = System.getenv("BILTHON_25_PASSWORD"); - public static final String BILTHON_11_BRAIN_KEY = System.getenv("BILTHON_11_BRAIN_KEY"); + public static final String BILTHON_11_BRAIN_KEY = System.getenv("BILTHON_11_BRAINKEY"); + + public static final String BILTHON_15_BRAIN_KEY = System.getenv("BILTHON_15_BRAINKEY"); + + public static final String BILTHON_16_BRAIN_KEY = System.getenv("BILTHON_16_BRAINKEY"); + + public static final String GENERIC_PASSWORD = System.getenv("GENERIC_PASSWORD"); // Static block information used for transaction serialization tests public static int REF_BLOCK_NUM = 56204; @@ -48,7 +54,7 @@ public class Main { // test.testGetDynamicParams(); // test.testGetRequiredFeesSerialization(); // test.testRequiredFeesResponse(); -// test.testTransactionBroadcastSequence(); + test.testTransactionBroadcastSequence(); // test.testAccountLookupDeserialization(); // test.testPrivateKeyManipulations(); // test.testPublicKeyManipulations(); @@ -65,7 +71,7 @@ public class Main { // test.testAccountUpdateSerialization(); // test.testAccountUpdateOperationBroadcast(); // test.testCreateBinFile(); - test.testImportBinFile(); +// test.testImportBinFile(); // test.testExportBinFile(); // test.testLzmaCompression(); // test.testLzmaDecompression(); diff --git a/app/src/main/java/de/bitsharesmunich/graphenej/Test.java b/app/src/main/java/de/bitsharesmunich/graphenej/Test.java index 8322619..b6b8647 100644 --- a/app/src/main/java/de/bitsharesmunich/graphenej/Test.java +++ b/app/src/main/java/de/bitsharesmunich/graphenej/Test.java @@ -1,6 +1,7 @@ package de.bitsharesmunich.graphenej; import com.google.common.primitives.Bytes; +import de.bitsharesmunich.graphenej.errors.MalformedOperationException; import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener; import de.bitsharesmunich.graphenej.models.*; import de.bitsharesmunich.graphenej.models.backup.LinkedAccount; @@ -16,6 +17,10 @@ import com.google.gson.reflect.TypeToken; import de.bitsharesmunich.graphenej.errors.MalformedAddressException; import de.bitsharesmunich.graphenej.errors.MalformedTransactionException; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; +import de.bitsharesmunich.graphenej.operations.AccountUpdateOperation; +import de.bitsharesmunich.graphenej.operations.AccountUpdateOperationBuilder; +import de.bitsharesmunich.graphenej.operations.TransferOperation; +import de.bitsharesmunich.graphenej.operations.TransferOperationBuilder; import de.bitsharesmunich.graphenej.test.NaiveSSLContext; import com.neovisionaries.ws.client.*; import de.bitsharesmunich.graphenej.api.*; @@ -43,8 +48,8 @@ public class Test { public static final String AMAZON_WITNESS = "ws://54.91.97.99:8090"; public static final String WITNESS_URL = "api://api.devling.xyz:8088"; public static final String OPENLEDGER_WITNESS_URL = "wss://bitshares.openledger.info/api"; - public static final String BLOCK_PAY_DE = "wss://de.blockpay.ch:8089"; - public static final String BLOCK_PAY_FR = "wss://fr.blockpay.ch:8089"; + public static final String BLOCK_PAY_DE = "wss://de.blockpay.ch/node"; + public static final String BLOCK_PAY_FR = "wss://fr.blockpay.ch/node"; private Transaction transaction; @@ -220,31 +225,6 @@ public class Test { System.out.println(Util.bytesToHex(account.toBytes())); } - public void testTransactionSerialization() { - try { - 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"))) - .setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0"))) - .setPrivateKey(DumpedPrivateKey.fromBase58(null, Main.WIF).getKey()) - .setBlockData(new BlockData(Main.REF_BLOCK_NUM, Main.REF_BLOCK_PREFIX, Main.RELATIVE_EXPIRATION)) - .build(); - - ArrayList transactionList = new ArrayList<>(); - transactionList.add(transaction); - - byte[] signature = transaction.getGrapheneSignature(); - System.out.println(Util.bytesToHex(signature)); - ApiCall call = new ApiCall(4, "call", "broadcast_transaction", transactionList, "2.0", 1); - String jsonCall = call.toJsonString(); - System.out.println("json call"); - System.out.println(jsonCall); - } catch (MalformedTransactionException e) { - System.out.println("MalformedTransactionException. Msg: " + e.getMessage()); - } - } - public void testLoginSerialization() { ArrayList loginParams = new ArrayList<>(); // loginParams.add("nelson"); @@ -292,7 +272,6 @@ public class Test { } public void testTransactionBroadcastSequence() { - String url = Test.OPENLEDGER_WITNESS_URL; WitnessResponseListener listener = new WitnessResponseListener() { @Override public void onSuccess(WitnessResponse response) { @@ -307,26 +286,38 @@ public class Test { }; try { - ECKey from = new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey(); - PublicKey to = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPublicKey())); + ECKey sourcePrivateKey = new BrainKey(Main.BILTHON_15_BRAIN_KEY, 0).getPrivateKey(); + PublicKey to1 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_5_BRAIN_KEY, 0).getPublicKey())); + PublicKey to2 = new PublicKey(ECKey.fromPublicOnly(new BrainKey(Main.BILTHON_16_BRAIN_KEY, 0).getPublicKey())); // Creating memo long nonce = 1; - byte[] encryptedMessage = Memo.encryptMessage(from, to, nonce, "another message"); - Memo memo = new Memo(new Address(ECKey.fromPublicOnly(from.getPubKey())), new Address(to.getKey()), nonce, encryptedMessage); + byte[] encryptedMessage = Memo.encryptMessage(sourcePrivateKey, to1, nonce, "another message"); + Memo memo = new Memo(new Address(ECKey.fromPublicOnly(sourcePrivateKey.getPubKey())), new Address(to1.getKey()), nonce, encryptedMessage); - // Creating transaction - Transaction transaction = new TransferTransactionBuilder() - .setSource(new UserAccount("1.2.138632")) // bilthon-83 + // Creating operation 1 + TransferOperation transferOperation1 = new TransferOperationBuilder() + .setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0"))) + .setSource(new UserAccount("1.2.143563")) // bilthon-15 .setDestination(new UserAccount("1.2.139313")) // bilthon-5 - .setAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0"))) .setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0"))) - .setPrivateKey(new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0).getPrivateKey()) - .setMemo(memo) .build(); - ArrayList transactionList = new ArrayList<>(); - transactionList.add(transaction); + // Creating operation 2 + TransferOperation transferOperation2 = new TransferOperationBuilder() + .setTransferAmount(new AssetAmount(UnsignedLong.valueOf(1), new Asset("1.3.0"))) + .setSource(new UserAccount("1.2.143563")) // bilthon-15 + .setDestination(new UserAccount("1.2.143569")) // bilthon-16 + .setFee(new AssetAmount(UnsignedLong.valueOf(264174), new Asset("1.3.0"))) + .build(); + + + // Adding operations to the operation list + ArrayList operationList = new ArrayList<>(); + operationList.add(transferOperation1); + operationList.add(transferOperation2); + + Transaction transaction = new Transaction(sourcePrivateKey, null, operationList); SSLContext context = null; context = NaiveSSLContext.getInstance("TLS"); @@ -340,7 +331,7 @@ public class Test { mWebSocket.addListener(new TransactionBroadcastSequence(transaction, new Asset("1.3.0"), listener)); mWebSocket.connect(); - } catch (MalformedTransactionException e) { + } catch (MalformedOperationException e) { System.out.println("MalformedTransactionException. Msg: " + e.getMessage()); } catch (IOException e) { System.out.println("IOException. Msg: " + e.getMessage()); @@ -363,15 +354,17 @@ public class Test { } public void testPrivateKeyManipulations() { - String brainKeyWords = "PUMPER ISOTOME SERE STAINER CLINGER MOONLIT CHAETA UPBRIM AEDILIC BERTHER NIT SHAP SAID SHADING JUNCOUS CHOUGH"; + String brainKeyWords = Main.BILTHON_15_BRAIN_KEY; + BrainKey brainKey = new BrainKey(brainKeyWords, 0); ECKey privateKey = DumpedPrivateKey.fromBase58(null, brainKey.getWalletImportFormat()).getKey(); - System.out.println("private key..............: " + Util.bytesToHex(privateKey.getSecretBytes())); - System.out.println("public key uncompressed..: " + Util.bytesToHex(privateKey.getPubKey())); - System.out.println("public key compressed....: " + Util.bytesToHex(privateKey.getPubKeyPoint().getEncoded(true))); - System.out.println("base58...................: " + Base58.encode(privateKey.getPubKeyPoint().getEncoded(true))); - System.out.println("base58...................: " + Base58.encode(privateKey.getPubKey())); + Address address = new Address(ECKey.fromPublicOnly(privateKey.getPubKey())); + System.out.println("Raw private key..........: " + Util.bytesToHex(privateKey.getSecretBytes())); + System.out.println("WIF private key..........: " + brainKey.getWalletImportFormat()); + System.out.println("Public key uncompressed..: " + Util.bytesToHex(privateKey.getPubKey())); + System.out.println("Public key compressed....: " + Util.bytesToHex(privateKey.getPubKeyPoint().getEncoded(true))); + System.out.println("Address..................: " + address.toString()); } public void testPublicKeyManipulations() { @@ -637,9 +630,10 @@ public class Test { } public void testImportBinFile() { + String password = Main.GENERIC_PASSWORD; try { String current = new File(".").getCanonicalPath(); - File file = new File(current + "/src/main/java/de/bitsharesmunich/graphenej/bts_bilthon-25_20170214.bin"); + File file = new File(current + "/bts_vinicius_default_20170218_20170219.bin"); Path path = Paths.get(file.getAbsolutePath()); byte[] data = Files.readAllBytes(path); byte[] publicKey = new byte[FileBin.PUBLIC_KEY_LENGTH]; @@ -647,22 +641,27 @@ public class Test { MessageDigest md = MessageDigest.getInstance("SHA-256"); ECKey randomECKey = ECKey.fromPublicOnly(publicKey); - byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(Main.BILTHON_25_PASSWORD.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded(); + byte[] finalKey = randomECKey.getPubKeyPoint().multiply(ECKey.fromPrivate(md.digest(password.getBytes("UTF-8"))).getPrivKey()).normalize().getXCoord().getEncoded(); + System.out.println("final key : "+Util.bytesToHex(finalKey)); + Address address = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(finalKey).getPubKey())); + System.out.println("address : "+address.toString()); - WalletBackup walletBackup = FileBin.deserializeWalletBackup(data, Main.BILTHON_25_PASSWORD); - System.out.println("Number of wallets: "+walletBackup.getWalletCount()); - String brainKeyString = walletBackup.getWallet(0).decryptBrainKey(Main.BILTHON_25_PASSWORD); + WalletBackup walletBackup = FileBin.deserializeWalletBackup(data, password); + String brainKeyString = walletBackup.getWallet(0).decryptBrainKey(password); System.out.println("Brain key: "+brainKeyString); BrainKey brainKey = new BrainKey(brainKeyString, 1); - byte[] privateKey = brainKey.getPrivateKey().getPrivKeyBytes(); - System.out.println("Brainkey derived private....: " + Util.bytesToHex(privateKey)); + byte[] brainKeyDerivedPrivateKey = brainKey.getPrivateKey().getPrivKeyBytes(); + System.out.println("Brainkey derived private....: " + Util.bytesToHex(brainKeyDerivedPrivateKey)); - byte[] privateKey2 = walletBackup.getPrivateKeyBackup(0).decryptPrivateKey(walletBackup.getWallet(0).getEncryptionKey(Main.BILTHON_25_PASSWORD)); - System.out.println("Encrypted private key.......: "+Util.bytesToHex(privateKey2)); + byte[] encryptionKey = walletBackup.getWallet(0).getEncryptionKey(password); + byte[] privateKey0 = walletBackup.getPrivateKeyBackup(0).decryptPrivateKey(encryptionKey); + byte[] privateKey1 = walletBackup.getPrivateKeyBackup(1).decryptPrivateKey(encryptionKey); + System.out.println("Encrypted private key 1.....: "+Util.bytesToHex(privateKey0)); + System.out.println("Encrypted private key 2.....: "+Util.bytesToHex(privateKey1)); - Address addr1 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey).getPubKey())); - Address addr2 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey2).getPubKey())); - Address addr3 = new Address(ECKey.fromPublicOnly(publicKey)); + Address addr1 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(brainKeyDerivedPrivateKey).getPubKey())); + Address addr2 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey0).getPubKey())); + Address addr3 = new Address(ECKey.fromPublicOnly(ECKey.fromPrivate(privateKey1).getPubKey())); System.out.println("Addr1: "+addr1.toString()); System.out.println("Addr2: "+addr2.toString()); System.out.println("Addr3: "+addr3.toString()); @@ -674,7 +673,7 @@ public class Test { } public void testExportBinFile(){ - String password = "123456"; + String password = Main.GENERIC_PASSWORD; BrainKey brainKey = new BrainKey(Main.BILTHON_11_BRAIN_KEY, 0); Wallet wallet = new Wallet("bilthon-11", brainKey.getBrainKey(), brainKey.getSequenceNumber(), Chains.BITSHARES.CHAIN_ID, password); byte[] privateKey = brainKey.getPrivateKey().getPrivKeyBytes(); @@ -692,7 +691,7 @@ public class Test { System.out.println("Serialized: "+Util.bytesToHex(serialized)); try { String current = new File(".").getCanonicalPath(); - String fullPath = current + "/scwall_bithon_11.bin"; + String fullPath = current + "/scwall_bilthon_11.bin"; System.out.println("Full path: "+fullPath); File file = new File(fullPath); FileOutputStream out = new FileOutputStream(file); @@ -787,21 +786,27 @@ public class Test { Authority authority = new Authority(1, authMap, null); AccountOptions options = new AccountOptions(address.getPublicKey()); BrainKey brainKey = new BrainKey(Main.BILTHON_83_BRAIN_KEY, 0); - Transaction transaction = new AccountUpdateTransactionBuilder(brainKey.getPrivateKey()) - .setAccont(new UserAccount("1.2.140994")) -// .setOwner(authority) + + AccountUpdateOperation operation = new AccountUpdateOperationBuilder() + .setAccount(new UserAccount("1.2.140994")) .setActive(authority) .setOptions(options) - .setBlockData(new BlockData(Main.REF_BLOCK_NUM, Main.REF_BLOCK_PREFIX, Main.RELATIVE_EXPIRATION)) .build(); + ArrayList opList = new ArrayList<>(); + opList.add(operation); + + BlockData blockData = new BlockData(Main.REF_BLOCK_NUM, Main.REF_BLOCK_PREFIX, Main.RELATIVE_EXPIRATION); + ECKey privateKey = brainKey.getPrivateKey(); + Transaction transaction = new Transaction(privateKey, blockData, opList); + System.out.println("Json object"); System.out.println(transaction.toJsonString()); System.out.println("Serialized transaction"); System.out.println(Util.bytesToHex(transaction.toBytes())); } catch (MalformedAddressException e) { System.out.println("MalformedAddressException. Msg: " + e.getMessage()); - } catch (MalformedTransactionException e) { + } catch (MalformedOperationException e) { System.out.println("MalformedTransactionException. Msg: " + e.getMessage()); } } diff --git a/app/src/test/java/de/bitsharesmunich/graphenej/AssetTest.java b/app/src/test/java/de/bitsharesmunich/graphenej/AssetTest.java deleted file mode 100644 index 81d01dc..0000000 --- a/app/src/test/java/de/bitsharesmunich/graphenej/AssetTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.bitsharesmunich.graphenej; - -import org.junit.*; - -import static org.junit.Assert.*; - -/** - * Created by nelson on 12/24/16. - */ -public class AssetTest { - - @org.junit.Test - public void equals() throws Exception { - Asset bts = new Asset("1.3.0"); - Asset bitUSD = new Asset("1.3.121"); - assertNotEquals("Different assets should not be equal", bts, bitUSD); - } - -} \ No newline at end of file diff --git a/app/src/test/java/de/bitsharesmunich/graphenej/AuthorityTest.java b/app/src/test/java/de/bitsharesmunich/graphenej/AuthorityTest.java deleted file mode 100644 index cc9846d..0000000 --- a/app/src/test/java/de/bitsharesmunich/graphenej/AuthorityTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.bitsharesmunich.graphenej; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.InputMismatchException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -/** - * Created by nelson on 12/16/16. - */ -public class AuthorityTest { - private Authority authority; - private Authority sameAuthority; - private Authority differentAuthority; - private Authority keyAuthority1; - private Authority keyAuthority2; - - @Before - public void setUp() throws Exception { - authority = new Authority(); - sameAuthority = new Authority(); - HashMap accountAuthorityMap = new HashMap<>(); - UserAccount userAccount = new UserAccount("1.2.20000"); - accountAuthorityMap.put(userAccount, 1); - differentAuthority = new Authority(1, null, accountAuthorityMap); - - Address address1 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); - Address address2 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); - PublicKey publicKey = address1.getPublicKey(); - PublicKey samePublicKey = address2.getPublicKey(); - HashMap keyMap1 = new HashMap<>(); - HashMap keyMap2 = new HashMap<>(); - keyMap1.put(publicKey, 1); - keyMap2.put(samePublicKey, 1); - keyAuthority1 = new Authority(1, keyMap1, null); - keyAuthority2 = new Authority(1, keyMap2, null); - - } - - @org.junit.Test - public void toBytes() throws Exception { - - } - - @Test - public void equals() throws Exception { - assertEquals("Equal authorities", authority, sameAuthority); - assertEquals("Different authorities ", authority, differentAuthority); - assertEquals("Two public keys with the same public key should be equal", keyAuthority1, keyAuthority2); - } - - @After - public void tearDown(){ - } -} \ No newline at end of file diff --git a/app/src/test/java/de/bitsharesmunich/graphenej/PublicKeyTest.java b/app/src/test/java/de/bitsharesmunich/graphenej/PublicKeyTest.java deleted file mode 100644 index fe6307a..0000000 --- a/app/src/test/java/de/bitsharesmunich/graphenej/PublicKeyTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.bitsharesmunich.graphenej; - -import org.bitcoinj.core.*; -import org.junit.*; - -import static org.junit.Assert.*; - -/** - * Created by nelson on 12/16/16. - */ -public class PublicKeyTest { - @Before - public void setUp() throws Exception { - - } - @org.junit.Test - public void equals() throws Exception { - Address address1 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); - Address address2 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); - Address address3 = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYp00"); - PublicKey pk1 = address1.getPublicKey(); - PublicKey pk2 = address2.getPublicKey(); - PublicKey pk3 = address3.getPublicKey(); - assertEquals("Public keys must be equal", pk1, pk2); - assertNotEquals("Public keys must not be equal", pk1, pk3); - } - - @After - public void tearDown() throws Exception { - - } - -} \ No newline at end of file diff --git a/app/src/test/java/de/bitsharesmunich/graphenej/objects/MemoTest.java b/app/src/test/java/de/bitsharesmunich/graphenej/objects/MemoTest.java deleted file mode 100644 index 33cd015..0000000 --- a/app/src/test/java/de/bitsharesmunich/graphenej/objects/MemoTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package de.bitsharesmunich.graphenej.objects; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import de.bitsharesmunich.graphenej.Address; -import de.bitsharesmunich.graphenej.Util; -import de.bitsharesmunich.graphenej.errors.ChecksumException; -import org.bitcoinj.core.DumpedPrivateKey; -import org.bitcoinj.core.ECKey; -import org.junit.*; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - -/** - * Created by nelson on 12/19/16. - */ -public class MemoTest { - - private ECKey sourcePrivate; - private Address sourceAddress; - - private ECKey destinationPrivate; - private Address destinationAddress; - - private long nonce; - private String shortMessage = "test"; - private String longerMessage = "testing now longer string!!"; - - private byte[] shortEncryptedMessage = Util.hexToBytes("4c81c2db6ebc61e3f9e0ead65c0559dd"); - private byte[] longerEncryptedMessage = Util.hexToBytes("1f8a08f1ff53dcefd48eeb052d26fba425f2a917f508ce61fc3d5696b10efa17"); - - private String decodedMessage; - - @Before - public void setUp() throws Exception { - sourcePrivate = DumpedPrivateKey.fromBase58(null, "5J96pne45qWM1WpektoeazN6k9Mt93jQ7LyueRxFfEMTiy6yxjM").getKey(); - destinationPrivate = DumpedPrivateKey.fromBase58(null, "5HuGQT8qwHScBgD4XsGbQUmXQF18MrbzxaQDiGGXFNRrCtqgT5Q").getKey(); - - sourceAddress = new Address("BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); - destinationAddress = new Address("BTS8ADjGaswhfFoxMGxqCdBtzhTBJsrGadCLoc9Ey5AGc8eoVZ5bV"); - - nonce = 5; - } - - @Test - public void shouldMatchPredefinedChiphertext(){ - byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); - assertArrayEquals("Testing with short message and nonce 1", encrypted, shortEncryptedMessage); - - byte[] encryptedLong = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, longerMessage); - assertArrayEquals("Testing with longer message and nonce 1", encryptedLong, longerEncryptedMessage); - } - - @Test - public void shouldEncryptAndDecryptShortMessage(){ - try { - byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, nonce, shortMessage); - String decrypted = decrypted = Memo.decryptMessage(destinationPrivate, sourceAddress, nonce, encrypted); - assertEquals("Decrypted message must be equal to original", decrypted, shortMessage); - } catch (ChecksumException e) { - e.printStackTrace(); - } - } - - @Test - public void shouldEncryptAndDecryptLongerMessage(){ - try{ - byte[] longEncrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, nonce, longerMessage); - String longDecrypted = Memo.decryptMessage(destinationPrivate, sourceAddress, nonce, longEncrypted); - assertEquals("The longer message must be equal to the original", longerMessage, longDecrypted); - } catch (ChecksumException e) { - e.printStackTrace(); - } - } - - @Test(expected = ChecksumException.class) - public void shouldThrowException() throws ChecksumException { - byte[] corrupted = Memo.encryptMessage(sourcePrivate, destinationAddress, nonce, longerMessage); - corrupted[0] = 0; - String longDecrypted = Memo.decryptMessage(destinationPrivate, sourceAddress, nonce, corrupted); - } - - @Test - public void shouldBeJsonObjectSerializable(){ - byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); - Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted); - JsonElement jsonObject = memo.toJsonObject(); - JsonObject reference = new JsonObject(); - reference.addProperty("from", "BTS8RiFgs8HkcVPVobHLKEv6yL3iXcC9SWjbPVS15dDAXLG9GYhnY"); - reference.addProperty("to", "BTS8ADjGaswhfFoxMGxqCdBtzhTBJsrGadCLoc9Ey5AGc8eoVZ5bV"); - reference.addProperty("nonce", "1"); - reference.addProperty("message", "4c81c2db6ebc61e3f9e0ead65c0559dd"); - assertEquals("Memo instance should generate a valid JsonObject",jsonObject, reference); - } - - @Test - public void shouldBeByteSerializable(){ - String byteReference = "0103d1fb8c7421db64d46fba7e36f428854ca06eff65698b293f37c7ffaa54e2c2b203aece7c31616c02fcc96b50d3397c0e8d33d6384655d477c300d9196c728a5ee20100000000000000104c81c2db6ebc61e3f9e0ead65c0559dd"; - byte[] encrypted = Memo.encryptMessage(sourcePrivate, destinationAddress, 1, shortMessage); - Memo memo = new Memo(sourceAddress, destinationAddress, 1, encrypted); - byte[] memoBytes = memo.toBytes(); - assertEquals("Memo instance should generate a valid byte array", byteReference, Util.bytesToHex(memoBytes)); - } -} \ No newline at end of file diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateTransactionBuilder.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateTransactionBuilder.java index 2fb6d56..0e05366 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateTransactionBuilder.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateTransactionBuilder.java @@ -1,6 +1,7 @@ package de.bitsharesmunich.graphenej; import de.bitsharesmunich.graphenej.errors.MalformedTransactionException; +import de.bitsharesmunich.graphenej.operations.AccountUpdateOperation; import org.bitcoinj.core.ECKey; import java.util.ArrayList; diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/BaseOperation.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/BaseOperation.java index fdbe9c7..caf1721 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/BaseOperation.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/BaseOperation.java @@ -9,9 +9,11 @@ import de.bitsharesmunich.graphenej.interfaces.JsonSerializable; public abstract class BaseOperation implements ByteSerializable, JsonSerializable { protected OperationType type; + protected Extensions extensions; public BaseOperation(OperationType type){ this.type = type; + this.extensions = new Extensions(); } public byte getId() { diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/Transaction.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/Transaction.java index a4c0068..13c3443 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/Transaction.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/Transaction.java @@ -5,6 +5,7 @@ import com.google.gson.*; import de.bitsharesmunich.graphenej.interfaces.ByteSerializable; import de.bitsharesmunich.graphenej.interfaces.JsonSerializable; +import de.bitsharesmunich.graphenej.operations.TransferOperation; import org.bitcoinj.core.DumpedPrivateKey; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.Sha256Hash; @@ -37,7 +38,7 @@ public class Transaction implements ByteSerializable, JsonSerializable { private ECKey privateKey; private BlockData blockData; private List operations; - private List extensions; + private Extensions extensions; /** * Transaction constructor. @@ -49,7 +50,7 @@ public class Transaction implements ByteSerializable, JsonSerializable { this.privateKey = privateKey; this.blockData = blockData; this.operations = operationList; - this.extensions = new ArrayList(); + this.extensions = new Extensions(); } /** @@ -172,17 +173,8 @@ public class Transaction implements ByteSerializable, JsonSerializable { byteArray.addAll(Bytes.asList(operation.toBytes())); } - //Adding the number of extensions - byteArray.add((byte) this.extensions.size()); - - 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 - // leave it here and work on signing the transaction. - //TODO: Investigate the origin and meaning of this last byte. - byteArray.add((byte) 0 ); + // Adding extensions byte + byteArray.addAll(Bytes.asList(this.extensions.toBytes())); return Bytes.toArray(byteArray); } diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/TransferTransactionBuilder.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/TransferTransactionBuilder.java deleted file mode 100644 index 88ba4c4..0000000 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/TransferTransactionBuilder.java +++ /dev/null @@ -1,101 +0,0 @@ -package de.bitsharesmunich.graphenej; - -import de.bitsharesmunich.graphenej.objects.Memo; -import de.bitsharesmunich.graphenej.errors.MalformedTransactionException; -import org.bitcoinj.core.ECKey; - -import java.util.ArrayList; -import java.util.List; - -/** - * Class used to build a transaction containing a transfer operation. - */ -public class TransferTransactionBuilder extends TransactionBuilder { - private List operations; - private UserAccount sourceAccount; - private UserAccount destinationAccount; - private AssetAmount transferAmount; - private AssetAmount feeAmount; - private Memo memo; - - public TransferTransactionBuilder(){} - - public TransferTransactionBuilder(ECKey privKey) { - super(privKey); - } - - public TransferTransactionBuilder setPrivateKey(ECKey key){ - this.privateKey = key; - return this; - } - - public TransferTransactionBuilder setBlockData(BlockData blockData){ - this.blockData = blockData; - return this; - } - - public TransferTransactionBuilder setSource(UserAccount source){ - this.sourceAccount = source; - return this; - } - - public TransferTransactionBuilder setDestination(UserAccount destination){ - this.destinationAccount = destination; - return this; - } - - public TransferTransactionBuilder setAmount(AssetAmount amount){ - this.transferAmount = amount; - return this; - } - - public TransferTransactionBuilder setFee(AssetAmount amount){ - this.feeAmount = amount; - return this; - } - - public TransferTransactionBuilder setMemo(Memo memo){ - this.memo = memo; - return this; - } - - //TODO: Add support for multiple transfer operations in a single transaction - public TransferTransactionBuilder addOperation(TransferOperation transferOperation){ - if(operations == null){ - operations = new ArrayList(); - } - return this; - } - - @Override - public Transaction build() throws MalformedTransactionException { - if(privateKey == null){ - throw new MalformedTransactionException("Missing private key information"); - }else if(operations == null){ - // If the operations list has not been set, we might be able to build one with the - // previously provided data. But in order for this to work we have to have all - // source, destination and transfer amount data. - operations = new ArrayList<>(); - if(sourceAccount == null){ - throw new MalformedTransactionException("Missing source account information"); - } - if(destinationAccount == null){ - throw new MalformedTransactionException("Missing destination account information"); - } - if(transferAmount == null){ - throw new MalformedTransactionException("Missing transfer amount information"); - } - TransferOperation transferOperation; - if(feeAmount == null){ - transferOperation = new TransferOperation(sourceAccount, destinationAccount, transferAmount); - }else{ - transferOperation = new TransferOperation(sourceAccount, destinationAccount, transferAmount, feeAmount); - } - if(memo != null){ - transferOperation.setMemo(this.memo); - } - operations.add(transferOperation); - } - return new Transaction(privateKey, blockData, operations); - } -} diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRelativeAccountHistory.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRelativeAccountHistory.java index 1887a56..5507263 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRelativeAccountHistory.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/GetRelativeAccountHistory.java @@ -5,7 +5,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import de.bitsharesmunich.graphenej.AssetAmount; import de.bitsharesmunich.graphenej.RPC; -import de.bitsharesmunich.graphenej.TransferOperation; +import de.bitsharesmunich.graphenej.operations.TransferOperation; import de.bitsharesmunich.graphenej.UserAccount; import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener; import de.bitsharesmunich.graphenej.models.ApiCall; diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java index f593a53..547236e 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/api/SubscriptionMessagesHub.java @@ -10,11 +10,10 @@ import com.neovisionaries.ws.client.WebSocketFrame; import de.bitsharesmunich.graphenej.AssetAmount; import de.bitsharesmunich.graphenej.RPC; import de.bitsharesmunich.graphenej.Transaction; -import de.bitsharesmunich.graphenej.TransferOperation; +import de.bitsharesmunich.graphenej.operations.TransferOperation; import de.bitsharesmunich.graphenej.interfaces.SubscriptionHub; import de.bitsharesmunich.graphenej.interfaces.SubscriptionListener; import de.bitsharesmunich.graphenej.models.ApiCall; -import de.bitsharesmunich.graphenej.models.BaseResponse; import de.bitsharesmunich.graphenej.models.SubscriptionResponse; import de.bitsharesmunich.graphenej.models.WitnessResponse; diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/errors/MalformedOperationException.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/errors/MalformedOperationException.java new file mode 100644 index 0000000..223f17c --- /dev/null +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/errors/MalformedOperationException.java @@ -0,0 +1,11 @@ +package de.bitsharesmunich.graphenej.errors; + +/** + * Created by nelson on 3/1/17. + */ +public class MalformedOperationException extends RuntimeException { + + public MalformedOperationException(String msg){ + super(msg); + } +} diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/HistoricalTransfer.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/HistoricalTransfer.java index 1237d65..44d09c0 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/HistoricalTransfer.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/models/HistoricalTransfer.java @@ -1,6 +1,6 @@ package de.bitsharesmunich.graphenej.models; -import de.bitsharesmunich.graphenej.TransferOperation; +import de.bitsharesmunich.graphenej.operations.TransferOperation; /** diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateOperation.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java similarity index 97% rename from graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateOperation.java rename to graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java index b97f230..5abe334 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/AccountUpdateOperation.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperation.java @@ -1,4 +1,4 @@ -package de.bitsharesmunich.graphenej; +package de.bitsharesmunich.graphenej.operations; import com.google.common.primitives.Bytes; import com.google.common.primitives.UnsignedLong; @@ -6,6 +6,7 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import de.bitsharesmunich.graphenej.*; /** * Class used to encapsulate operations related to the ACCOUNT_UPDATE_OPERATION. diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationBuilder.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationBuilder.java new file mode 100644 index 0000000..f7a088a --- /dev/null +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/AccountUpdateOperationBuilder.java @@ -0,0 +1,59 @@ +package de.bitsharesmunich.graphenej.operations; + +import de.bitsharesmunich.graphenej.*; +import de.bitsharesmunich.graphenej.errors.MalformedOperationException; + +/** + * Created by nelson on 3/1/17. + */ +public class AccountUpdateOperationBuilder extends BaseOperationBuilder { + private AssetAmount fee; + private UserAccount account; + private Authority owner; + private Authority active; + private AccountOptions new_options; + + public AccountUpdateOperationBuilder setFee(AssetAmount fee) { + this.fee = fee; + return this; + } + + public AccountUpdateOperationBuilder setAccount(UserAccount account) { + this.account = account; + return this; + } + + public AccountUpdateOperationBuilder setOwner(Authority owner) { + this.owner = owner; + return this; + } + + public AccountUpdateOperationBuilder setActive(Authority active) { + this.active = active; + return this; + } + + public AccountUpdateOperationBuilder setOptions(AccountOptions newOptions) { + this.new_options = newOptions; + return this; + } + + @Override + public AccountUpdateOperation build() { + AccountUpdateOperation operation; + if(this.account == null){ + throw new MalformedOperationException("This operation requires an account to be set"); + }else{ + if(owner != null || active != null || new_options != null){ + if(fee == null){ + operation = new AccountUpdateOperation(account, owner, active, new_options); + }else{ + operation = new AccountUpdateOperation(account, owner, active, new_options, fee); + } + }else{ + throw new MalformedOperationException("This operation requires at least either an authority or account options change"); + } + } + return operation; + } +} diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/BaseOperationBuilder.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/BaseOperationBuilder.java new file mode 100644 index 0000000..82eed94 --- /dev/null +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/BaseOperationBuilder.java @@ -0,0 +1,17 @@ +package de.bitsharesmunich.graphenej.operations; + +import de.bitsharesmunich.graphenej.BaseOperation; + +/** + * Base template for all operation-specific factory classes. + */ +public abstract class BaseOperationBuilder { + + /** + * Must be implemented and return the specific operation the + * factory is supposed to build. + * + * @return: A usable instance of a given operation. + */ + public abstract BaseOperation build(); +} diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/TransferOperation.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/TransferOperation.java similarity index 95% rename from graphenej/src/main/java/de/bitsharesmunich/graphenej/TransferOperation.java rename to graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/TransferOperation.java index 10c3acf..73ddbc9 100644 --- a/graphenej/src/main/java/de/bitsharesmunich/graphenej/TransferOperation.java +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/TransferOperation.java @@ -1,5 +1,9 @@ -package de.bitsharesmunich.graphenej; +package de.bitsharesmunich.graphenej.operations; +import de.bitsharesmunich.graphenej.AssetAmount; +import de.bitsharesmunich.graphenej.BaseOperation; +import de.bitsharesmunich.graphenej.OperationType; +import de.bitsharesmunich.graphenej.UserAccount; import de.bitsharesmunich.graphenej.objects.Memo; import com.google.common.primitives.Bytes; import com.google.gson.*; @@ -22,7 +26,6 @@ public class TransferOperation extends BaseOperation { private UserAccount from; private UserAccount to; private Memo memo; - private String[] extensions; public TransferOperation(UserAccount from, UserAccount to, AssetAmount transferAmount, AssetAmount fee){ super(OperationType.TRANSFER_OPERATION); @@ -81,7 +84,8 @@ public class TransferOperation extends BaseOperation { byte[] toBytes = to.toBytes(); byte[] amountBytes = amount.toBytes(); byte[] memoBytes = memo.toBytes(); - return Bytes.concat(feeBytes, fromBytes, toBytes, amountBytes, memoBytes); + byte[] extensions = this.extensions.toBytes(); + return Bytes.concat(feeBytes, fromBytes, toBytes, amountBytes, memoBytes, extensions); } @Override diff --git a/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/TransferOperationBuilder.java b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/TransferOperationBuilder.java new file mode 100644 index 0000000..c080734 --- /dev/null +++ b/graphenej/src/main/java/de/bitsharesmunich/graphenej/operations/TransferOperationBuilder.java @@ -0,0 +1,63 @@ +package de.bitsharesmunich.graphenej.operations; + +import de.bitsharesmunich.graphenej.AssetAmount; +import de.bitsharesmunich.graphenej.UserAccount; +import de.bitsharesmunich.graphenej.errors.MalformedOperationException; +import de.bitsharesmunich.graphenej.objects.Memo; + +/** + * Factory class used to build a transfer operation + */ +public class TransferOperationBuilder extends BaseOperationBuilder { + private UserAccount from; + private UserAccount to; + private AssetAmount transferAmount; + private AssetAmount fee; + private Memo memo; + + public TransferOperationBuilder setSource(UserAccount from) { + this.from = from; + return this; + } + + public TransferOperationBuilder setDestination(UserAccount to) { + this.to = to; + return this; + } + + public TransferOperationBuilder setTransferAmount(AssetAmount transferAmount) { + this.transferAmount = transferAmount; + return this; + } + + public TransferOperationBuilder setFee(AssetAmount fee) { + this.fee = fee; + return this; + } + + public TransferOperationBuilder setMemo(Memo memo) { + this.memo = memo; + return this; + } + + @Override + public TransferOperation build(){ + TransferOperation transferOperation; + if(from == null ){ + throw new MalformedOperationException("Missing source account information"); + }else if(to == null){ + throw new MalformedOperationException("Missing destination account information"); + }else if(transferAmount == null){ + throw new MalformedOperationException("Missing transfer amount information"); + } + if(fee != null){ + transferOperation = new TransferOperation(from, to, transferAmount, fee); + }else{ + transferOperation = new TransferOperation(from, to, transferAmount); + } + if(memo != null){ + transferOperation.setMemo(this.memo); + } + return transferOperation; + } +}