diff --git a/node_config.properties b/node_config.properties index f3c3793..e5e5a5a 100644 --- a/node_config.properties +++ b/node_config.properties @@ -1,5 +1,5 @@ iota.node.protocol=http #iota.node.host=138.68.126.141 -iota.node.host=127.0.0.1 +iota.node.host=node.iotawallet.info iota.node.port=14265 diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index b742299..617de2e 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -14,7 +14,9 @@ import retrofit2.converter.gson.GsonConverterFactory; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -184,19 +186,69 @@ public class IotaAPIProxy { return wrapCheckedException(res).body(); } - // end of proxied calls. - public BroadcastTransactionsResponse broadcastTransactions(String... trytes) { final Call res = service.broadcastTransactions(IotaBroadcastTransactionRequest.createBroadcastTransactionsRequest(trytes)); return wrapCheckedException(res).body(); } + // end of proxied calls. + public GetBundleResponse getBundle(String transaction) { return IotaAPIUtils.getBundle(transaction); } + + /** + * Generates a new address from a seed and returns the remainderAddress. + * This is either done deterministically, or by providing the index of the new remainderAddress + * + * @param seed Tryte-encoded seed. It should be noted that this seed is not transferred + * @param index Optional (default null). Key index to start search from. If the index is provided, the generation of the address is not deterministic. + * @param checksum Optional (default false). Adds 9-tryte address checksum + * @param total Optional (default 1)Total number of addresses to generate + * @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(String seed, Integer securityLevel) { - return IotaAPIUtils.getNewAddress(seed, securityLevel); + 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 + + for (int i = index; ; i++) { + 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) { + allAddresses.subList(0, allAddresses.size()-1).clear(); + } + + return GetNewAddressResponse.create(allAddresses); } public static class Builder { diff --git a/src/main/java/jota/dto/response/GetNewAddressResponse.java b/src/main/java/jota/dto/response/GetNewAddressResponse.java index dab7d86..b54384d 100644 --- a/src/main/java/jota/dto/response/GetNewAddressResponse.java +++ b/src/main/java/jota/dto/response/GetNewAddressResponse.java @@ -1,16 +1,18 @@ package jota.dto.response; +import java.util.List; + public class GetNewAddressResponse extends AbstractResponse { - private String address; + private List addresses; - public String getAddress() { - return address; - } - - public static GetNewAddressResponse create(String address) { + public static GetNewAddressResponse create(List addresses) { GetNewAddressResponse res = new GetNewAddressResponse(); - res.address = address; + res.addresses = addresses; return res; } + + public List getAddress() { + return addresses; + } } diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 47e5567..10a49de 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -1,5 +1,7 @@ package jota.utils; +import org.apache.commons.lang3.StringUtils; + /** * Created by pinpong on 02.12.16. */ @@ -15,7 +17,8 @@ public class Checksum { public static String removeChecksum(String addressWithChecksum) { if (isAddressWithChecksum(addressWithChecksum)) { return getAddress(addressWithChecksum); - } else return ""; + } + return StringUtils.EMPTY; } private static String getAddress(String addressWithChecksum) { diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 277a0ca..ed5f2ef 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -11,8 +11,9 @@ public class InputValidator { } public static boolean checkAddress(String address) { - if (!isAddress(address)) + if (!isAddress(address)) { throw new RuntimeException("Invalid address: " + address); + } return true; } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index dd47181..3da5c2d 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,7 +1,6 @@ package jota.utils; import jota.dto.response.GetBundleResponse; -import jota.dto.response.GetNewAddressResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,17 +14,30 @@ public class IotaAPIUtils { private static final Logger log = LoggerFactory.getLogger(IotaAPIUtils.class); - public static GetNewAddressResponse getNewAddress(final String seed, final int index) { + /** + * Generates a new address + * + * @param seed + * @param index + * @param checksum + * @return an String with address + */ + public static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); final int[] digests = Signing.digests(key); final int[] addressTrits = Signing.address(digests); - final String address = Converter.trytes(addressTrits); - return GetNewAddressResponse.create(address); + String address = Converter.trytes(addressTrits); + + if (checksum) { + address = Checksum.addChecksum(address); + } + return address; } public static GetBundleResponse getBundle(final String transaction) { throw new NotImplementedException("Not yet implemented"); } } + diff --git a/src/main/java/jota/utils/IotaUnits.java b/src/main/java/jota/utils/IotaUnits.java index f3fbfe0..28e52f3 100644 --- a/src/main/java/jota/utils/IotaUnits.java +++ b/src/main/java/jota/utils/IotaUnits.java @@ -3,6 +3,10 @@ package jota.utils; /** * Created by pinpong on 30.11.16. */ + +/** + * Table of IOTA units based off of the standard system of Units + **/ public enum IotaUnits { IOTA("i", 0), KILO_IOTA("Ki", 3), diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 3cff61c..025529e 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -8,27 +8,25 @@ public class Signing { static int[] key(int[] seed, int index, int length) { - final int[] subseed = seed; - for (int i = 0; i < index; i++) { for (int j = 0; j < 243; j++) { - if (++subseed[j] > 1) { - subseed[j] = -1; + if (++seed[j] > 1) { + seed[j] = -1; } else { break; } } } - Curl curl = new Curl(); + final Curl curl = new Curl(); curl.reset(); - curl.absorb(subseed, 0, subseed.length); - curl.squeeze(subseed, 0, subseed.length); + curl.absorb(seed, 0, seed.length); + curl.squeeze(seed, 0, seed.length); curl.reset(); - curl.absorb(subseed, 0, subseed.length); + curl.absorb(seed, 0, seed.length); - List key = new ArrayList<>(); - int[] buffer = new int[subseed.length]; + final List key = new ArrayList<>(); + int[] buffer = new int[seed.length]; int offset = 0; while (length-- > 0) { @@ -70,19 +68,14 @@ public class Signing { curl.absorb(buffer, 0, buffer.length); curl.squeeze(buffer, 0, buffer.length); } - for (int k = 0; k < 243; k++) { - - keyFragment[j * 243 + k] = buffer[k]; - } + System.arraycopy(buffer, 0, keyFragment, j * 243, 243); } curl.reset(); curl.absorb(keyFragment, 0, keyFragment.length); curl.squeeze(buffer, 0, buffer.length); - for (int j = 0; j < 243; j++) { - digests[i * 243 + j] = buffer[j]; - } + System.arraycopy(buffer, 0, digests, i * 243, 243); } return digests; } diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java index 4751b4a..21f560e 100644 --- a/src/main/java/jota/utils/TrytesConverter.java +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -36,7 +36,7 @@ public class TrytesConverter { public static String toTrytes(String inputString) { - String trytes = ""; + StringBuilder trytes = new StringBuilder(); for (int i = 0; i < inputString.length(); i++) { @@ -52,10 +52,10 @@ public class TrytesConverter { String trytesValue = String.valueOf(Constants.TRYTE_ALPHABET.charAt(firstValue) + String.valueOf(Constants.TRYTE_ALPHABET.charAt(secondValue))); - trytes += trytesValue; + trytes.append(trytesValue); } - return trytes; + return trytes.toString(); } /** diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index 69825c0..1413f69 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -22,4 +22,9 @@ public class ChecksumTest { public void shouldRemoveChecksum() { assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); } + + @Test + public void shouldIsValidChecksum() { + assertEquals(Checksum.isValidChecksum(TEST_ADDRESS_WITH_CHECKSUM), true); + } } diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index b8cd2c7..9b16cda 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,12 +3,13 @@ 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; import org.junit.Test; -import static org.junit.Assert.assertEquals; +import java.util.Collections; + import static org.junit.Assert.assertThat; /** @@ -74,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()); } @@ -96,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()); } @@ -114,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()); } @@ -127,6 +128,7 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { - assertEquals(IotaAPIUtils.getNewAddress(TEST_SEED, 0).getAddress(), TEST_ADDRESS_WITH_CHECKSUM); + 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