From 9173bb9fb6c71500b065e27b590987edc053347a Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Wed, 7 Dec 2016 15:19:24 +0100 Subject: [PATCH 1/3] updated tests (#8) --- src/main/java/jota/utils/IotaAPIUtils.java | 10 ++------ src/test/java/jota/AddressGenerationTest.java | 20 --------------- src/test/java/jota/IotaAPIProxyTest.java | 25 ++++++++----------- 3 files changed, 13 insertions(+), 42 deletions(-) delete mode 100644 src/test/java/jota/AddressGenerationTest.java diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index d53fba5..3da5c2d 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,11 +1,10 @@ package jota.utils; +import jota.dto.response.GetBundleResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jota.dto.response.GetBundleResponse; - /** * Client Side computation service * @@ -26,14 +25,9 @@ public class IotaAPIUtils { public static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); - log.debug("key Length = {}", key.length ); - final int[] digests = Signing.digests(key); - log.debug("digests Length = {}", digests.length ); - final int[] addressTrits = Signing.address(digests); - log.debug("addressTrits Length = {}", addressTrits.length ); - + String address = Converter.trytes(addressTrits); if (checksum) { diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java deleted file mode 100644 index 3dfddea..0000000 --- a/src/test/java/jota/AddressGenerationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package jota; - -import jota.utils.IotaAPIUtils; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Created by Adrian on 02.12.2016. - */ -public class AddressGenerationTest { - private static String TEST_SEED = "ZEB99QTOMYDSKIFCXTLTVSWQFKO9CRKQKMRDR9HWVOVSGZMWPFQIMSCXXWUULHD9MZKMFJZAYZHZYA9VZ"; - private static String FIRST_ADDRESS = "LCZXWAQUHBXST9IEPPMJICTWLKJA9HVASXWDIRCVNM9TUAGZY9SRRJLZMZQIZKBAESXXNABFATUAYQYYW"; - - @Test - public void shouldAddChecksum() { - assertEquals(IotaAPIUtils.newAddress(TEST_SEED,0, false),FIRST_ADDRESS); - } - -} diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 6a153ab..9b16cda 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,8 +3,6 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; -import jota.utils.IotaAPIUtils; - import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Before; @@ -12,7 +10,6 @@ import org.junit.Test; import java.util.Collections; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; /** @@ -78,19 +75,19 @@ public class IotaAPIProxyTest { @Test public void shouldFindTransactionsByApprovees() { - FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{TEST_HASH}); assertThat(trans, IsNull.notNullValue()); } @Test public void shouldFindTransactionsByBundles() { - FindTransactionResponse trans = proxy.findTransactionsByBundles(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByBundles(TEST_HASH); assertThat(trans, IsNull.notNullValue()); } @Test public void shouldFindTransactionsByDigests() { - FindTransactionResponse trans = proxy.findTransactionsByDigests(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByDigests(TEST_HASH); assertThat(trans, IsNull.notNullValue()); } @@ -100,13 +97,13 @@ public class IotaAPIProxyTest { @Test public void shouldGetTrytes() { GetTrytesResponse res = proxy.getTrytes(TEST_HASH); - assertThat(res, IsNull.nullValue()); + assertThat(res, IsNull.notNullValue()); + } @Test public void shouldGetInclusionStates() { - GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, - new String[]{"123"}); + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); assertThat(res, IsNull.notNullValue()); } @@ -118,7 +115,7 @@ public class IotaAPIProxyTest { @Test public void shouldGetBalances() { - GetBalancesResponse res = proxy.getBalances(100, new String[]{"HBBYKAKTILIPVUKFOTSLHGENPTXYBNKXZFQFR9VQFWNBMTQNRVOUKPVPRNBSZVVILMAFBKOTBLGLWLOHQ"}); + GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); System.err.println(res); assertThat(res, IsNull.notNullValue()); } @@ -129,9 +126,9 @@ public class IotaAPIProxyTest { assertThat(proxy, IsNull.notNullValue()); } - /*@Test TODO Fix me + @Test public void shouldCreateANewAddress() { - final GetNewAddressResponse res = proxy.newAddress(TEST_SEED, 4, false); - assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); - }*/ + final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); + assertThat(res.getAddress(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + } } \ No newline at end of file From 9dc1947234492fa81335c7b5c6a255392baf2cdb Mon Sep 17 00:00:00 2001 From: davassi Date: Wed, 7 Dec 2016 17:34:09 +0100 Subject: [PATCH 2/3] some refactoring --- src/main/java/jota/IotaAPIProxy.java | 25 +++++++------------- src/main/java/jota/{utils => pow}/Curl.java | 2 +- src/main/java/jota/utils/Checksum.java | 2 ++ src/main/java/jota/utils/InputValidator.java | 2 +- src/main/java/jota/utils/Signing.java | 2 ++ 5 files changed, 14 insertions(+), 19 deletions(-) rename src/main/java/jota/{utils => pow}/Curl.java (98%) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 617de2e..5ce6806 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -208,48 +208,39 @@ public class IotaAPIProxy { * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) * @return an array of strings with the specifed number of addresses */ - public GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { final List allAddresses = new ArrayList<>(); - // Case 1: total - // + // If total number of addresses to generate is supplied, simply generate // and return the list of all addresses - if (total != 0) { - // Increase index with each iteration for (int i = index; i < index + total; i++) { allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); } return GetNewAddressResponse.create(allAddresses); } - - // Case 2: no total provided - // - // Continue calling findTransactions to see if address was already created - // if null, return list of addresses - + // No total provided: Continue calling findTransactions to see if address was + // already created if null, return list of addresses for (int i = index; ; i++) { - String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); - + + final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); allAddresses.add(newAddress); - if (response.getHashes().length == 0) { break; } } - // If returnAll, return list of allAddresses - // else return only the last address that was generated + // If !returnAll return only the last address that was generated if (!returnAll) { allAddresses.subList(0, allAddresses.size()-1).clear(); } - return GetNewAddressResponse.create(allAddresses); } + + public static class Builder { diff --git a/src/main/java/jota/utils/Curl.java b/src/main/java/jota/pow/Curl.java similarity index 98% rename from src/main/java/jota/utils/Curl.java rename to src/main/java/jota/pow/Curl.java index 2c296e8..d72ed45 100644 --- a/src/main/java/jota/utils/Curl.java +++ b/src/main/java/jota/pow/Curl.java @@ -1,4 +1,4 @@ -package jota.utils; +package jota.pow; /** * (c) 2016 Come-from-Beyond diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 10a49de..fe22f5a 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -2,6 +2,8 @@ package jota.utils; import org.apache.commons.lang3.StringUtils; +import jota.pow.Curl; + /** * Created by pinpong on 02.12.16. */ diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index ed5f2ef..c1ddd2a 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -17,7 +17,7 @@ public class InputValidator { return true; } - public static boolean isTrytes(String trytes, int length) { + public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } } diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 025529e..a5e2553 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import jota.pow.Curl; + public class Signing { static int[] key(int[] seed, int index, int length) { From 21ddac09d0b93078493ab3ce0408e50a577edaa2 Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Wed, 14 Dec 2016 11:06:06 +0100 Subject: [PATCH 3/3] updated and added new Utils (#9) * added SeedRandomGenerator * extended IotaUnitConverter * minor * added isArrayOfHashes * renamed constants * added error package * added transactionObject * fixed IotaUnitConverter --- .../java/jota/error/ArgumentException.java | 10 ++ src/main/java/jota/error/BaseException.java | 51 +++++++ .../jota/error/NotEnoughBalanceException.java | 10 ++ src/main/java/jota/model/Transaction.java | 141 ++++++++++++------ src/main/java/jota/utils/Checksum.java | 4 +- src/main/java/jota/utils/Constants.java | 6 +- src/main/java/jota/utils/Converter.java | 63 +++++++- src/main/java/jota/utils/InputValidator.java | 22 ++- .../java/jota/utils/IotaUnitConverter.java | 53 ++++++- .../java/jota/utils/SeedRandomGenerator.java | 20 +++ src/main/java/jota/utils/TrytesConverter.java | 8 +- src/test/java/jota/IotaUnitConverterTest.java | 20 +++ .../java/jota/SeedRandomGeneratorTest.java | 22 +++ 13 files changed, 368 insertions(+), 62 deletions(-) create mode 100644 src/main/java/jota/error/ArgumentException.java create mode 100644 src/main/java/jota/error/BaseException.java create mode 100644 src/main/java/jota/error/NotEnoughBalanceException.java create mode 100644 src/main/java/jota/utils/SeedRandomGenerator.java create mode 100644 src/test/java/jota/SeedRandomGeneratorTest.java diff --git a/src/main/java/jota/error/ArgumentException.java b/src/main/java/jota/error/ArgumentException.java new file mode 100644 index 0000000..759b694 --- /dev/null +++ b/src/main/java/jota/error/ArgumentException.java @@ -0,0 +1,10 @@ +package jota.error; + +/** + * Created by Adrian on 09.12.2016. + */ +public class ArgumentException extends BaseException { + public ArgumentException() { + super("wrong arguments passed to function"); + } +} diff --git a/src/main/java/jota/error/BaseException.java b/src/main/java/jota/error/BaseException.java new file mode 100644 index 0000000..b1eb210 --- /dev/null +++ b/src/main/java/jota/error/BaseException.java @@ -0,0 +1,51 @@ +package jota.error; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * Created by Adrian on 09.12.2016. + */ +public class BaseException extends Exception { + protected Collection messages; + + public BaseException(String msg) { + super(msg); + } + + + public BaseException(String msg, Exception cause) { + super(msg, cause); + } + + + public BaseException(Collection messages) { + super(); + this.messages = messages; + } + + + public BaseException(Collection messages, Exception cause) { + super(cause); + this.messages = messages; + } + + @Override + public String getMessage() { + String msg; + + if (this.messages != null && !this.messages.isEmpty()) { + msg = "["; + + for (String message : this.messages) { + msg += message + ","; + } + + msg = StringUtils.removeEnd(msg, ",") + "]"; + + } else msg = super.getMessage(); + + return msg; + } +} diff --git a/src/main/java/jota/error/NotEnoughBalanceException.java b/src/main/java/jota/error/NotEnoughBalanceException.java new file mode 100644 index 0000000..c7099d6 --- /dev/null +++ b/src/main/java/jota/error/NotEnoughBalanceException.java @@ -0,0 +1,10 @@ +package jota.error; + +/** + * Created by Adrian on 09.12.2016. + */ +public class NotEnoughBalanceException extends BaseException { + public NotEnoughBalanceException() { + super("not enough balance dude"); + } +} diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 4cf5e89..8a74f5a 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -7,36 +7,38 @@ import org.apache.commons.lang3.builder.ToStringStyle; * Created by pinpong on 02.12.16. */ public class Transaction { - - private String signatureMessageChunk; - private String index; - private String approvalNonce; private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; + private String signatureFragments; private String address; private String value; + private String tag; + private String timestamp; + private String currentIndex; + private String lastIndex; private String bundle; + private String trunkTransaction; + private String branchTransaction; + private String nonce; + private Boolean persistence; - public Transaction(String signatureMessageChunk, String index, String approvalNonce, String hash, String digest, String type, String timestamp, String trunkTransaction, String branchTransaction, String signatureNonce, String address, String value, String bundle) { + public Transaction() { + + } + + public Transaction(String signatureFragments, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { this.hash = hash; - this.type = type; - this.signatureMessageChunk = signatureMessageChunk; - this.digest = digest; + this.tag = tag; + this.signatureFragments = signatureFragments; this.address = address; this.value = value; this.timestamp = timestamp; - this.index = index; + this.currentIndex = currentIndex; + this.lastIndex = lastIndex; this.bundle = bundle; - this.signatureNonce = signatureNonce; - this.approvalNonce = approvalNonce; this.trunkTransaction = trunkTransaction; this.branchTransaction = branchTransaction; + this.nonce = nonce; } @Override @@ -44,56 +46,107 @@ public class Transaction { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); } - public String getValue() { - return value; + public String getHash() { + return hash; } - public String getDigest() { - return digest; + public void setHash(String hash) { + this.hash = hash; } - public String getTrunkTransaction() { - return trunkTransaction; + public String getSignatureFragments() { + return signatureFragments; } - public String getTimestamp() { - return timestamp; - } - - public String getSignatureNonce() { - return signatureNonce; - } - - public String getType() { - return type; + public String setSignatureFragments(String signatureFragments) { + return this.signatureFragments = signatureFragments; } public String getAddress() { return address; } - public String getApprovalNonce() { - return approvalNonce; + public void setAddress(String address) { + this.address = address; } - public String getBranchTransaction() { - return branchTransaction; + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getCurrentIndex() { + return currentIndex; + } + + public String setCurrentIndex(String currentIndex) { + return this.currentIndex = currentIndex; + } + + public String getLastIndex() { + return lastIndex; + } + + public String setLastIndex(String lastIndex) { + return this.lastIndex = lastIndex; } public String getBundle() { return bundle; } - public String getHash() { - return hash; + public void setBundle(String bundle) { + this.bundle = bundle; } - public String getIndex() { - return index; + public String getTrunkTransaction() { + return trunkTransaction; } - public String getSignatureMessageChunk() { - return signatureMessageChunk; + public void setTrunkTransaction(String trunkTransaction) { + this.trunkTransaction = trunkTransaction; } -} + public String getBranchTransaction() { + return branchTransaction; + } + + public void setBranchTransaction(String branchTransaction) { + this.branchTransaction = branchTransaction; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public Boolean getPersistence() { + return persistence; + } + + public void setPersistence(Boolean persistence) { + this.persistence = persistence; + } +} \ No newline at end of file diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index fe22f5a..6bf83f5 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -24,7 +24,7 @@ public class Checksum { } private static String getAddress(String addressWithChecksum) { - return addressWithChecksum.substring(0, Constants.addressLengthWithoutChecksum); + return addressWithChecksum.substring(0, Constants.ADDRESS_LENGTH_WITHOUT_CHECKSUM); } public static boolean isValidChecksum(String addressWithChecksum) { @@ -34,7 +34,7 @@ public class Checksum { } private static boolean isAddressWithChecksum(String addressWithChecksum) { - return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.addressLengthWithChecksum; + return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.ADDRESS_LENGTH_WITH_CHECKSUM; } public static String calculateChecksum(String address) { diff --git a/src/main/java/jota/utils/Constants.java b/src/main/java/jota/utils/Constants.java index 997b296..2b9d4a5 100644 --- a/src/main/java/jota/utils/Constants.java +++ b/src/main/java/jota/utils/Constants.java @@ -7,7 +7,9 @@ public class Constants { public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public static int addressLengthWithoutChecksum = 81; - public static int addressLengthWithChecksum = 90; + public static final int SEED_LENGTH_MAX = 81; + + public static int ADDRESS_LENGTH_WITHOUT_CHECKSUM = 81; + public static int ADDRESS_LENGTH_WITH_CHECKSUM = 90; } diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index a43388f..0a94107 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -1,16 +1,19 @@ package jota.utils; +import jota.model.Transaction; +import jota.pow.Curl; + import java.util.Arrays; public class Converter { - public static final int RADIX = 3; - public static final int MAX_TRIT_VALUE = (RADIX - 1) / 2, MIN_TRIT_VALUE = -MAX_TRIT_VALUE; + private static final int RADIX = 3; + private static final int MAX_TRIT_VALUE = (RADIX - 1) / 2, MIN_TRIT_VALUE = -MAX_TRIT_VALUE; - public static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; - public static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; - static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; - static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; + private static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; + private static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; + private static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; + private static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; static { @@ -94,7 +97,7 @@ public class Converter { public static int[] copyTrits(final String input, final int[] destination) { for (int i = 0; i < input.length(); i++) { int index = Constants.TRYTE_ALPHABET.indexOf(input.charAt(i)); - destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS [index][0]; + destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS[index][0]; destination[i * 3 + 1] = TRYTE_TO_TRITS_MAPPINGS[index][1]; destination[i * 3 + 2] = TRYTE_TO_TRITS_MAPPINGS[index][2]; } @@ -124,6 +127,15 @@ public class Converter { return trits[offset] + trits[offset + 1] * 3 + trits[offset + 2] * 9; } + public static int value(final int[] trits) { + int value = 0; + + for (int i = trits.length; i-- > 0; ) { + value = value * 3 + trits[i]; + } + return value; + } + public static void increment(final int[] trits, final int size) { for (int i = 0; i < size; i++) { @@ -134,4 +146,41 @@ public class Converter { } } } + + public static Transaction transactionObject(String trytes) { + if (trytes == null) return null; + + // validity check + for (int i = 2279; i < 2295; i++) { + if (trytes.charAt(i) != '9') { + return null; + } + } + int[] transactionTrits = Converter.trits(trytes); + int[] hash = new int[90]; + + Curl curl = new Curl(); + + // generate the correct transaction hash + curl.reset(); + curl.absorb(transactionTrits, 0, transactionTrits.length); + curl.squeeze(hash, 0, hash.length); + + Transaction trx = new Transaction(); + + trx.setHash(Converter.trytes(hash)); + trx.setSignatureFragments(trytes.substring(0, 2187)); + trx.setAddress(trytes.substring(2187, 2268)); + trx.setValue("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6804, 6837))); + trx.setTag(trytes.substring(2295, 2322)); + trx.setTimestamp("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6966, 6993))); + trx.setCurrentIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6993, 7020))); + trx.setLastIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 7020, 7047))); + trx.setBundle(trytes.substring(2349, 2430)); + trx.setTrunkTransaction(trytes.substring(2430, 2511)); + trx.setBranchTransaction(trytes.substring(2511, 2592)); + trx.setNonce(trytes.substring(2592, 2673)); + + return trx; + } } \ No newline at end of file diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index c1ddd2a..d658bd3 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -6,8 +6,8 @@ package jota.utils; public class InputValidator { public static boolean isAddress(String address) { - return (address.length() == Constants.addressLengthWithoutChecksum || - address.length() == Constants.addressLengthWithChecksum) && isTrytes(address, address.length()); + return (address.length() == Constants.ADDRESS_LENGTH_WITHOUT_CHECKSUM || + address.length() == Constants.ADDRESS_LENGTH_WITH_CHECKSUM) && isTrytes(address, address.length()); } public static boolean checkAddress(String address) { @@ -20,4 +20,22 @@ public class InputValidator { public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } + + public static boolean isArrayOfHashes(String[] hashes) { + if (hashes == null) return false; + + for (String hash : hashes) { + // Check if address with checksum + if (hash.length() == 90) { + if (!isTrytes(hash, 90)) { + return false; + } + } else { + if (!isTrytes(hash, 81)) { + return false; + } + } + } + return true; + } } diff --git a/src/main/java/jota/utils/IotaUnitConverter.java b/src/main/java/jota/utils/IotaUnitConverter.java index 57271e8..cdd4529 100644 --- a/src/main/java/jota/utils/IotaUnitConverter.java +++ b/src/main/java/jota/utils/IotaUnitConverter.java @@ -1,7 +1,9 @@ package jota.utils; +import java.text.DecimalFormat; + /** - * Created by pinpong on 30.11.16. + * Created by Sascha on 30.11.16. */ public class IotaUnitConverter { @@ -13,4 +15,53 @@ public class IotaUnitConverter { private static long convertUnits(long amount, IotaUnits toUnit) { return (long) (amount / Math.pow(10, toUnit.getValue())); } + + public static String convertRawIotaAmountToDisplayText(long amount) { + IotaUnits unit = findOptimalIotaUnitToDisplay(amount); + double amountInDisplayUnit = convertAmountTo(amount, unit); + return createAmountWithUnitDisplayText(amountInDisplayUnit, unit); + } + + public static double convertAmountTo(long amount, IotaUnits target) { + return amount / Math.pow(10, target.getValue()); + } + + private static String createAmountWithUnitDisplayText(double amountInUnit, IotaUnits unit) { + String result = createAmountDisplayText(amountInUnit, unit); + result += " " + unit.getUnit(); + return result; + } + + public static String createAmountDisplayText(double amountInUnit, IotaUnits unit) { + DecimalFormat df = new DecimalFormat("##0.##################"); + String result = ""; + // display unit as integer if value is between 1-999 or in decimal format + result += unit == IotaUnits.IOTA ? (long) amountInUnit : df.format(amountInUnit); + return result; + } + + public static IotaUnits findOptimalIotaUnitToDisplay(long amount) { + int length = String.valueOf(amount).length(); + + if (amount < 0) // do not count "-" sign + length -= 1; + + IotaUnits units = IotaUnits.IOTA; + + if (length >= 1 && length <= 3) { + units = IotaUnits.IOTA; + } else if (length > 3 && length <= 6) { + units = IotaUnits.KILO_IOTA; + } else if (length > 6 && length <= 9) { + units = IotaUnits.MEGA_IOTA; + } else if (length > 9 && length <= 12) { + units = IotaUnits.GIGA_IOTA; + } else if (length > 12 && length <= 15) { + units = IotaUnits.TERA_IOTA; + } else if (length > 15 && length <= 18) { + units = IotaUnits.PETA_IOTA; + } + return units; + } + } diff --git a/src/main/java/jota/utils/SeedRandomGenerator.java b/src/main/java/jota/utils/SeedRandomGenerator.java new file mode 100644 index 0000000..8e702cb --- /dev/null +++ b/src/main/java/jota/utils/SeedRandomGenerator.java @@ -0,0 +1,20 @@ +package jota.utils; + +import java.util.Random; + +/** + * Created by pinpong on 13.12.16. + */ +public class SeedRandomGenerator { + + public static String generateNewSeed() { + char[] chars = Constants.TRYTE_ALPHABET.toCharArray(); + StringBuilder builder = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < Constants.SEED_LENGTH_MAX; i++) { + char c = chars[random.nextInt(chars.length)]; + builder.append(c); + } + return builder.toString(); + } +} diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java index 21f560e..5c5d843 100644 --- a/src/main/java/jota/utils/TrytesConverter.java +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -70,7 +70,7 @@ public class TrytesConverter { public static String toString(String inputTrytes) { - String string = ""; + StringBuilder string = new StringBuilder(); for (int i = 0; i < inputTrytes.length(); i += 2) { // get a trytes pair @@ -82,9 +82,9 @@ public class TrytesConverter { String character = Character.toString((char) decimalValue); - string += character; + string.append(character); } - return string; + return string.toString(); } -} +} \ No newline at end of file diff --git a/src/test/java/jota/IotaUnitConverterTest.java b/src/test/java/jota/IotaUnitConverterTest.java index 5078ac5..81da852 100644 --- a/src/test/java/jota/IotaUnitConverterTest.java +++ b/src/test/java/jota/IotaUnitConverterTest.java @@ -35,4 +35,24 @@ public class IotaUnitConverterTest { public void shouldConvertUnitTiToPi() { assertEquals(IotaUnitConverter.convertUnits(1000, IotaUnits.TERA_IOTA, IotaUnits.PETA_IOTA), 1); } + + @Test + public void shouldFindOptimizeUnitToDisplay() { + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1), IotaUnits.IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000), IotaUnits.KILO_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000), IotaUnits.MEGA_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000000), IotaUnits.GIGA_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000000000L), IotaUnits.TERA_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000000000000L), IotaUnits.PETA_IOTA); + } + + @Test + public void shouldConvertRawIotaAmountToDisplayText() { + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1), "1 i"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000), "1 Ki"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000), "1 Mi" ); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000), "1 Gi" ); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000000L), "1 Ti"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000000000L), "1 Pi"); + } } diff --git a/src/test/java/jota/SeedRandomGeneratorTest.java b/src/test/java/jota/SeedRandomGeneratorTest.java new file mode 100644 index 0000000..b2ab6d2 --- /dev/null +++ b/src/test/java/jota/SeedRandomGeneratorTest.java @@ -0,0 +1,22 @@ +package jota; + +import jota.utils.Constants; +import jota.utils.InputValidator; +import jota.utils.SeedRandomGenerator; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 13.12.16. + */ +public class SeedRandomGeneratorTest { + + @Test + public void shouldGenerateNewSeed() { + + String generatedSeed = SeedRandomGenerator.generateNewSeed(); + assertEquals(InputValidator.isAddress(generatedSeed), true); + assertEquals(generatedSeed.length(), Constants.SEED_LENGTH_MAX); + } +}