diff --git a/node_config.properties b/node_config.properties index fd80f02..fbd32d9 100644 --- a/node_config.properties +++ b/node_config.properties @@ -1,7 +1,7 @@ iota.node.protocol=http -#iota.node.host=node.iotawallet.info +iota.node.host=node.iotawallet.info #iota.node.host=138.68.90.186 #iota.node.host=192.168.11.2 -iota.node.host=138.68.90.186 +#iota.node.host=138.68.90.186 iota.node.port=14265 diff --git a/pom.xml b/pom.xml index d3b98e8..3be12e9 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,11 @@ 4.12 test + + net.java.dev.jna + jna-platform + 4.0.0 + diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPI.java similarity index 68% rename from src/main/java/jota/IotaAPIProxy.java rename to src/main/java/jota/IotaAPI.java index b1b6ad8..717f277 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPI.java @@ -1,34 +1,23 @@ package jota; -import jota.dto.request.*; import jota.dto.response.*; import jota.error.ArgumentException; import jota.error.InvalidBundleException; import jota.error.InvalidSignatureException; import jota.model.*; -import jota.pow.Curl; -import jota.utils.Converter; -import jota.utils.InputValidator; -import jota.utils.IotaAPIUtils; -import jota.utils.Signing; -import okhttp3.OkHttpClient; +import jota.pow.ICurl; +import jota.pow.JCurl; +import jota.utils.*; +import jota.utils.StopWatch; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.StopWatch; +import org.apache.commons.lang3.time.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import retrofit2.Call; -import retrofit2.Response; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; import java.util.*; -import java.util.concurrent.TimeUnit; /** - * IotaAPIProxy Builder. Usage: + * IotaAPI Builder. Usage: *

* IotaApiProxy api = IotaApiProxy.Builder * .protocol("http") @@ -40,167 +29,23 @@ import java.util.concurrent.TimeUnit; * * @author davassi */ -public class IotaAPIProxy { +public class IotaAPI { - private static final Logger log = LoggerFactory.getLogger(IotaAPIProxy.class); + private static final Logger log = LoggerFactory.getLogger(IotaAPI.class); + private IotaAPICoreProxy coreProxy; + private ICurl customCurl; + private StopWatch stopWatch; - private IotaAPIService service; - private String protocol, host, port; - - private IotaAPIProxy(final Builder builder) { - protocol = builder.protocol; - host = builder.host; - port = builder.port; - postConstruct(); + public IotaAPI() { + this(null); } - protected static Response wrapCheckedException(final Call call) { - try { - final Response res = call.execute(); - if (res.code() == 400) { - throw new IllegalAccessError(res.errorBody().toString()); - } - return res; - } catch (IOException e) { - log.error("Execution of the API call raised exception. IOTA Node not reachable?", e); - throw new IllegalStateException(e.getMessage()); - } + public IotaAPI(ICurl customCurl) { + this.customCurl = customCurl; + coreProxy = new IotaAPICoreProxy.Builder().build(); + stopWatch = new StopWatch(); } - private static final String env(String env, String def) { - final String value = System.getenv(env); - if (value == null) { - log.warn("Environment variable '{}' is not defined, and actual value has not been specified. " - + "Rolling back to default value: '{}'", env, def); - return def; - } - return value; - } - - private void postConstruct() { - - final String nodeUrl = protocol + "://" + host + ":" + port; - - final OkHttpClient client = new OkHttpClient.Builder() - .readTimeout(5000, TimeUnit.SECONDS) - .connectTimeout(5000, TimeUnit.SECONDS) - .build(); - - final Retrofit retrofit = new Retrofit.Builder() - .baseUrl(nodeUrl) - .addConverterFactory(GsonConverterFactory.create()) - .client(client) - .build(); - - service = retrofit.create(IotaAPIService.class); - - log.debug("Jota-API Java proxy pointing to node url: '{}'", nodeUrl); - } - - public GetNodeInfoResponse getNodeInfo() { - final Call res = service.getNodeInfo(IotaCommandRequest.createNodeInfoRequest()); - return wrapCheckedException(res).body(); - } - - public GetNeighborsResponse getNeighbors() { - final Call res = service.getNeighbors(IotaCommandRequest.createGetNeighborsRequest()); - return wrapCheckedException(res).body(); - } - - public AddNeighborsResponse addNeighbors(String... uris) { - final Call res = service.addNeighbors(IotaNeighborsRequest.createAddNeighborsRequest(uris)); - return wrapCheckedException(res).body(); - } - - public RemoveNeighborsResponse removeNeighbors(String... uris) { - final Call res = service.removeNeighbors(IotaNeighborsRequest.createRemoveNeighborsRequest(uris)); - return wrapCheckedException(res).body(); - } - - public GetTipsResponse getTips() { - final Call res = service.getTips(IotaCommandRequest.createGetTipsRequest()); - return wrapCheckedException(res).body(); - } - - public FindTransactionResponse findTransactions(String[] addresses, String[] tags, String[] approvees, String[] bundles) { - - final IotaFindTransactionsRequest findTransRequest = IotaFindTransactionsRequest - .createFindTransactionRequest() - .byAddresses(addresses) - .byTags(tags) - .byApprovees(approvees) - .byBundles(bundles); - - final Call res = service.findTransactions(findTransRequest); - return wrapCheckedException(res).body(); - } - - public FindTransactionResponse findTransactionsByAddresses(final String... addresses) { - return findTransactions(addresses, null, null, null); - } - - public FindTransactionResponse findTransactionsByBundles(final String... bundles) { - return findTransactions(null, null, null, bundles); - } - - public FindTransactionResponse findTransactionsByApprovees(final String... approvees) { - return findTransactions(null, null, approvees, null); - } - - public FindTransactionResponse findTransactionsByDigests(final String... digests) { - return findTransactions(null, digests, null, null); - } - - public GetInclusionStateResponse getInclusionStates(String[] transactions, String[] tips) { - final Call res = service.getInclusionStates(IotaGetInclusionStateRequest - .createGetInclusionStateRequest(transactions, tips)); - return wrapCheckedException(res).body(); - } - - public GetInclusionStateResponse getInclusionStates(Collection transactions, Collection tips) { - final Call res = service.getInclusionStates(IotaGetInclusionStateRequest - .createGetInclusionStateRequest(transactions, tips)); - return wrapCheckedException(res).body(); - } - - public GetTrytesResponse getTrytes(String... hashes) { - final Call res = service.getTrytes(IotaGetTrytesRequest.createGetTrytesRequest(hashes)); - return wrapCheckedException(res).body(); - } - - public GetTransactionsToApproveResponse getTransactionsToApprove(Integer depth) { - final Call res = service.getTransactionsToApprove(IotaGetTransactionsToApproveRequest.createIotaGetTransactionsToApproveRequest(depth)); - return wrapCheckedException(res).body(); - } - - public GetBalancesResponse getBalances(Integer threshold, String[] addresses) { - final Call res = service.getBalances(IotaGetBalancesRequest.createIotaGetBalancesRequest(threshold, addresses)); - return wrapCheckedException(res).body(); - } - - public GetBalancesResponse getBalances(Integer threshold, List addresses) { - return getBalances(threshold, addresses.toArray(new String[]{})); - } - - public InterruptAttachingToTangleResponse interruptAttachingToTangle() { - final Call res = service.interruptAttachingToTangle(IotaCommandRequest.createInterruptAttachToTangleRequest()); - return wrapCheckedException(res).body(); - } - - public GetAttachToTangleResponse attachToTangle(String trunkTransaction, String branchTransaction, Integer minWeightMagnitude, String... trytes) { - final Call res = service.attachToTangle(IotaAttachToTangleRequest.createAttachToTangleRequest(trunkTransaction, branchTransaction, minWeightMagnitude, trytes)); - return wrapCheckedException(res).body(); - } - - public StoreTransactionsResponse storeTransactions(String... trytes) { - final Call res = service.storeTransactions(IotaStoreTransactionsRequest.createStoreTransactionsRequest(trytes)); - return wrapCheckedException(res).body(); - } - - public BroadcastTransactionsResponse broadcastTransactions(String... trytes) { - final Call res = service.broadcastTransactions(IotaBroadcastTransactionRequest.createBroadcastTransactionsRequest(trytes)); - return wrapCheckedException(res).body(); - } // end of proxied calls. @@ -216,6 +61,7 @@ public class IotaAPIProxy { * @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) { + StopWatch stopWatch = new StopWatch(); List allAddresses = new ArrayList<>(); @@ -225,14 +71,14 @@ public class IotaAPIProxy { for (int i = index; i < index + total; i++) { allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); } - return GetNewAddressResponse.create(allAddresses); + return GetNewAddressResponse.create(allAddresses, stopWatch.getElapsedTimeMili()); } // No total provided: Continue calling findTransactions to see if address was // already created if null, return list of addresses for (int i = index; ; i++) { final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); - final FindTransactionResponse response = findTransactionsByAddresses(newAddress); + final FindTransactionResponse response = coreProxy.findTransactionsByAddresses(newAddress); allAddresses.add(newAddress); if (response.getHashes().length == 0) { @@ -246,7 +92,7 @@ public class IotaAPIProxy { //allAddresses = allAddresses.subList(allAddresses.size() - 2, allAddresses.size() - 1); allAddresses = allAddresses.subList(allAddresses.size() - 1, allAddresses.size()); } - return GetNewAddressResponse.create(allAddresses); + return GetNewAddressResponse.create(allAddresses, stopWatch.getElapsedTimeMili()); } /** @@ -260,8 +106,9 @@ public class IotaAPIProxy { * @returns {object} success **/ public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + StopWatch stopWatch = new StopWatch(); // validate & if needed pad seed - if ( (seed = InputValidator.validateSeed(seed)) == null) { + if ((seed = InputValidator.validateSeed(seed)) == null) { throw new IllegalStateException("Invalid Seed"); } @@ -273,22 +120,19 @@ public class IotaAPIProxy { throw new ArgumentException(); } StopWatch sw = new StopWatch(); - sw.start(); + System.out.println("GetTransfer started"); GetNewAddressResponse gnr = getNewAddress(seed, start, false, end == null ? end - start : end, true); if (gnr != null && gnr.getAddresses() != null) { - System.out.println("GetTransfers after getNewAddresses " + sw.getTime() + " ms"); + System.out.println("GetTransfers after getNewAddresses " + sw.getElapsedTimeMili() + " ms"); Bundle[] bundles = bundlesFromAddresses(gnr.getAddresses().toArray(new String[gnr.getAddresses().size()]), inclusionStates); - System.out.println("GetTransfers after bundlesFromAddresses " + sw.getTime() + " ms"); - sw.stop(); - - return GetTransferResponse.create(bundles); + System.out.println("GetTransfers after bundlesFromAddresses " + sw.getElapsedTimeMili() + " ms"); + return GetTransferResponse.create(bundles, stopWatch.getElapsedTimeMili()); } - sw.stop(); return null; } - public Bundle[] bundlesFromAddresses(String[] addresses, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { List trxs = findTransactionObjects(addresses); // set of tail transactions @@ -316,8 +160,8 @@ public class IotaAPIProxy { } } - List finalBundles = new ArrayList<>(); - String[] tailTxArray = tailTransactions.toArray(new String[tailTransactions.size()]); + final List finalBundles = new ArrayList<>(); + final String[] tailTxArray = tailTransactions.toArray(new String[tailTransactions.size()]); // If inclusionStates, get the confirmation status // of the tail transactions, and thus the bundles @@ -328,39 +172,34 @@ public class IotaAPIProxy { } catch (IllegalAccessError e) { } - if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) return null; + if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) + throw new ArgumentException("Inclusion states not found"); } - for (String trx : tailTxArray) { - try { - GetBundleResponse bundleResponse = getBundle(trx); - // TODO: review possibly dirty WA - if (bundleResponse == null) continue; - Bundle gbr = new Bundle(bundleResponse.getTransactions(), bundleResponse.getTransactions().size()); - if (gbr != null && gbr.getTransactions() != null) { - if (inclusionStates) { - boolean thisInclusion = gisr.getStates()[Arrays.asList(tailTxArray).indexOf(trx)]; - for (Transaction t : gbr.getTransactions()) { - t.setPersistence(thisInclusion); + final GetInclusionStateResponse finalInclusionStates = gisr; + Parallel.For(Arrays.asList(tailTxArray), + new Parallel.Operation() { + public void perform(String param) { + + try { + GetBundleResponse bundleResponse = getBundle(param); + Bundle gbr = new Bundle(bundleResponse.getTransactions(), bundleResponse.getTransactions().size()); + if (gbr != null && gbr.getTransactions() != null) { + if (inclusionStates) { + boolean thisInclusion = finalInclusionStates.getStates()[Arrays.asList(tailTxArray).indexOf(param)]; + for (Transaction t : gbr.getTransactions()) { + t.setPersistence(thisInclusion); + } + } + finalBundles.add(gbr); + } + // If error returned from getBundle, simply ignore it because the bundle was most likely incorrect + } catch (InvalidBundleException | ArgumentException | InvalidSignatureException e) { + log.warn("GetBundleError: ", e); } } - finalBundles.add(gbr); - } - // If error returned from getBundle, simply ignore it because the bundle was most likely incorrect - } catch (InvalidBundleException | ArgumentException | InvalidSignatureException e) { - log.warn("GetBundleError: ", e); - } + }); - } - - Collections.sort(finalBundles, new Comparator() { - public int compare(Bundle c1, Bundle c2) { - if (Long.parseLong(c1.getTransactions().get(0).getTimestamp()) < Long.parseLong(c2.getTransactions().get(0).getTimestamp())) - return -1; - if (Long.parseLong(c1.getTransactions().get(0).getTimestamp()) > Long.parseLong(c2.getTransactions().get(0).getTimestamp())) - return 1; - return 0; - } - }); + Collections.sort(finalBundles); Bundle[] returnValue = new Bundle[finalBundles.size()]; for (int i = 0; i < finalBundles.size(); i++) { returnValue[i] = new Bundle(finalBundles.get(i).getTransactions(), finalBundles.get(i).getTransactions().size()); @@ -375,12 +214,12 @@ public class IotaAPIProxy { public StoreTransactionsResponse broadcastAndStore(final String... trytes) { try { - broadcastTransactions(trytes); + coreProxy.broadcastTransactions(trytes); } catch (Exception e) { log.error("Impossible to broadcastAndStore, aborting.", e); throw new IllegalStateException("BroadcastAndStore Illegal state Exception"); } - return storeTransactions(trytes); + return coreProxy.storeTransactions(trytes); } /** @@ -392,10 +231,10 @@ public class IotaAPIProxy { * @return */ public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { - final GetTransactionsToApproveResponse txs = getTransactionsToApprove(depth); + final GetTransactionsToApproveResponse txs = coreProxy.getTransactionsToApprove(depth); // attach to tangle - do pow - final GetAttachToTangleResponse res = attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); + final GetAttachToTangleResponse res = coreProxy.attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); try { broadcastAndStore(res.getTrytes()); @@ -429,7 +268,7 @@ public class IotaAPIProxy { throw new IllegalStateException("Not an Array of Hashes: " + Arrays.toString(hashes)); } - final GetTrytesResponse trytesResponse = getTrytes(hashes); + final GetTrytesResponse trytesResponse = coreProxy.getTrytes(hashes); final List trxs = new ArrayList<>(); @@ -450,7 +289,7 @@ public class IotaAPIProxy { * @returns {object} success **/ public List findTransactionObjects(String[] input) { - FindTransactionResponse ftr = findTransactions(input, null, null, null); + FindTransactionResponse ftr = coreProxy.findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) return null; @@ -469,7 +308,7 @@ public class IotaAPIProxy { * @returns {object} success **/ public List findTransactionObjectsByBundle(String[] input) { - FindTransactionResponse ftr = findTransactions(null, null, null, input); + FindTransactionResponse ftr = coreProxy.findTransactions(null, null, null, input); if (ftr == null || ftr.getHashes() == null) return null; @@ -498,7 +337,7 @@ public class IotaAPIProxy { } // validate & if needed pad seed - if ( (seed = InputValidator.validateSeed(seed)) == null) { + if ((seed = InputValidator.validateSeed(seed)) == null) { throw new IllegalStateException("Invalid Seed"); } @@ -578,7 +417,7 @@ public class IotaAPIProxy { inputsAddresses.add(i.getAddress()); } - GetBalancesResponse balancesResponse = getBalances(100, inputsAddresses); + GetBalancesResponse balancesResponse = coreProxy.getBalances(100, inputsAddresses); String[] balances = balancesResponse.getBalances(); List confirmedInputs = new ArrayList<>(); @@ -643,14 +482,14 @@ public class IotaAPIProxy { * @property {int} threshold Min balance required **/ public GetBalancesAndFormatResponse getInputs(String seed, final List balances, int start, int end, int threshold) { - + StopWatch stopWatch = new StopWatch(); // validate the seed if (!InputValidator.isTrytes(seed, 0)) { throw new IllegalStateException("Invalid Seed"); } // validate & if needed pad seed - if ( (seed = InputValidator.validateSeed(seed)) == null) { + if ((seed = InputValidator.validateSeed(seed)) == null) { throw new IllegalStateException("Invalid Seed"); } @@ -674,7 +513,7 @@ public class IotaAPIProxy { allAddresses.add(address); } - return getBalanceAndFormat(allAddresses, balances, threshold, start, end); + return getBalanceAndFormat(allAddresses, balances, threshold, start, end, stopWatch); } // Case 2: iterate till threshold || end // @@ -682,18 +521,17 @@ public class IotaAPIProxy { // Calls getNewAddress and deterministically generates and returns all addresses // We then do getBalance, format the output and return it else { - final GetNewAddressResponse res = getNewAddress(seed, start, false, 0, true); - return getBalanceAndFormat(res.getAddresses(), balances, threshold, start, end); + return getBalanceAndFormat(res.getAddresses(), balances, threshold, start, end, stopWatch); } } // Calls getBalances and formats the output // returns the final inputsObject then - public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, List balances, long threshold, int start, int end) { + public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, List balances, long threshold, int start, int end, StopWatch stopWatch) { if (balances == null || balances.isEmpty()) { - GetBalancesResponse getBalancesResponse = getBalances(100, addresses); + GetBalancesResponse getBalancesResponse = coreProxy.getBalances(100, addresses); balances = Arrays.asList(getBalancesResponse.getBalances()); } @@ -724,7 +562,8 @@ public class IotaAPIProxy { } if (thresholdReached) { - return GetBalancesAndFormatResponse.create(inputs, totalBalance); + long duration = stopWatch.getElapsedTimeMili(); + return GetBalancesAndFormatResponse.create(inputs, totalBalance, stopWatch.getElapsedTimeMili()); } throw new IllegalStateException("Not enough balance"); } @@ -738,17 +577,18 @@ public class IotaAPIProxy { * @returns {list} bundle Transaction objects **/ public GetBundleResponse getBundle(String transaction) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + StopWatch stopWatch = new StopWatch(); Bundle bundle = traverseBundle(transaction, null, new Bundle()); if (bundle == null) { - return null; + throw new ArgumentException("Unknown Bundle"); } long totalSum = 0; int lastIndex = 0; String bundleHash = bundle.getTransactions().get(0).getBundle(); - Curl curl = new Curl(); + ICurl curl = new JCurl(); curl.reset(); List signaturesToValidate = new ArrayList<>(); @@ -765,7 +605,7 @@ public class IotaAPIProxy { String trxTrytes = Converter.transactionTrytes(trx).substring(2187, 2187 + 162); //System.out.println("Bundlesize "+bundle.getTransactions().size()+" "+trxTrytes); // Absorb bundle hash + value + timestamp + lastIndex + currentIndex trytes. - curl.absorb(Converter.trits(trxTrytes)); + curl.absorbb(Converter.trits(trxTrytes)); // Check if input transaction if (bundleValue < 0) { String address = trx.getAddress(); @@ -790,7 +630,7 @@ public class IotaAPIProxy { // Check for total sum, if not equal 0 return error if (totalSum != 0) throw new InvalidBundleException("Invalid Bundle Sum"); int[] bundleFromTrxs = new int[243]; - curl.squeeze(bundleFromTrxs); + curl.squeezee(bundleFromTrxs); String bundleFromTxString = Converter.trytes(bundleFromTrxs); // Check if bundle hash is the same as returned by tx object @@ -809,7 +649,7 @@ public class IotaAPIProxy { if (!isValidSignature) throw new InvalidSignatureException(); } - return GetBundleResponse.create(bundle.getTransactions()); + return GetBundleResponse.create(bundle.getTransactions(), stopWatch.getElapsedTimeMili()); } /** @@ -823,6 +663,7 @@ public class IotaAPIProxy { * @returns {object} analyzed Transaction objects **/ public ReplayBundleResponse replayBundle(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, ArgumentException, InvalidSignatureException { + StopWatch stopWatch = new StopWatch(); List bundleTrytes = new ArrayList<>(); @@ -839,13 +680,13 @@ public class IotaAPIProxy { for (int i = 0; i < trxs.size(); i++) { - final FindTransactionResponse response = findTransactionsByBundles(trxs.get(i).getBundle()); + final FindTransactionResponse response = coreProxy.findTransactionsByBundles(trxs.get(i).getBundle()); successful[i] = response.getHashes().length != 0; } - return ReplayBundleResponse.create(successful); + return ReplayBundleResponse.create(successful, stopWatch.getElapsedTimeMili()); } /** @@ -857,15 +698,16 @@ public class IotaAPIProxy { * @returns {array} state **/ public GetInclusionStateResponse getLatestInclusion(String[] hashes) { - GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); + GetNodeInfoResponse getNodeInfoResponse = coreProxy.getNodeInfo(); if (getNodeInfoResponse == null) return null; String[] latestMilestone = {getNodeInfoResponse.getLatestSolidSubtangleMilestone()}; - return getInclusionStates(hashes, latestMilestone); + return coreProxy.getInclusionStates(hashes, latestMilestone); } public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, final List transfers, Input[] inputs, String address) { + StopWatch stopWatch = new StopWatch(); List trytes = prepareTransfers(seed, transfers, address, inputs == null ? null : Arrays.asList(inputs)); List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), depth, minWeightMagnitude); @@ -874,12 +716,12 @@ public class IotaAPIProxy { for (int i = 0; i < trxs.size(); i++) { - final FindTransactionResponse response = findTransactionsByBundles(trxs.get(i).getBundle()); + final FindTransactionResponse response = coreProxy.findTransactionsByBundles(trxs.get(i).getBundle()); successful[i] = response.getHashes().length != 0; } - return SendTransferResponse.create(successful); + return SendTransferResponse.create(successful, stopWatch.getElapsedTimeMili()); } /** @@ -894,7 +736,7 @@ public class IotaAPIProxy { * @returns {array} bundle Transaction objects **/ public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { - GetTrytesResponse gtr = getTrytes(trunkTx); + GetTrytesResponse gtr = coreProxy.getTrytes(trunkTx); if (gtr != null) { @@ -934,6 +776,23 @@ public class IotaAPIProxy { } } + public String findTailTransactionHash(String hash) throws ArgumentException { + GetTrytesResponse gtr = coreProxy.getTrytes(hash); + + if (gtr == null) throw new ArgumentException("Invalid hash"); + + if (gtr.getTrytes().length == 0) { + throw new ArgumentException("Bundle transactions not visible"); + } + + Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]); + if (trx == null || trx.getBundle() == null) { + throw new ArgumentException("Invalid trytes, could not create object"); + } + if (Integer.parseInt(trx.getCurrentIndex()) == 0) return trx.getHash(); + else return findTailTransactionHash(trx.getBundle()); + } + public List addRemainder(final String seed, final List inputs, final Bundle bundle, @@ -986,75 +845,4 @@ public class IotaAPIProxy { } return null; } - - public static class Builder { - - String protocol, host, port; - - public IotaAPIProxy build() { - - if (protocol == null || host == null || port == null) { - - // check properties files. - if (!checkPropertiesFiles()) { - - // last resort: best effort on enviroment variable, - // before assigning default values. - checkEnviromentVariables(); - } - } - - return new IotaAPIProxy(this); - } - - private boolean checkPropertiesFiles() { - - try { - - FileReader fileReader = new FileReader("node_config.properties"); - BufferedReader bufferedReader = new BufferedReader(fileReader); - - final Properties nodeConfig = new Properties(); - nodeConfig.load(bufferedReader); - - if (nodeConfig.getProperty("iota.node.protocol") != null) { - protocol = nodeConfig.getProperty("iota.node.protocol"); - } - - if (nodeConfig.getProperty("iota.node.host") != null) { - host = nodeConfig.getProperty("iota.node.host"); - } - - if (nodeConfig.getProperty("iota.node.port") != null) { - port = nodeConfig.getProperty("iota.node.port"); - } - - } catch (IOException e1) { - log.debug("node_config.properties not found. Rolling back for another solution..."); - } - return (port != null && protocol != null && host != null); - } - - private void checkEnviromentVariables() { - protocol = env("IOTA_NODE_PROTOCOL", "http"); - host = env("IOTA_NODE_HOST", "localhost"); - port = env("IOTA_NODE_PORT", "14265"); - } - - public Builder host(String host) { - this.host = host; - return this; - } - - public Builder port(String port) { - this.port = port; - return this; - } - - public Builder protocol(String protocol) { - this.protocol = protocol; - return this; - } - - } } diff --git a/src/main/java/jota/IotaAPICoreProxy.java b/src/main/java/jota/IotaAPICoreProxy.java new file mode 100644 index 0000000..2be14bd --- /dev/null +++ b/src/main/java/jota/IotaAPICoreProxy.java @@ -0,0 +1,260 @@ +package jota; + +import jota.dto.request.*; +import jota.dto.response.*; +import okhttp3.OkHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +/** + * Created by Adrian on 15.01.2017. + */ +public class IotaAPICoreProxy { + + private static final Logger log = LoggerFactory.getLogger(IotaAPICoreProxy.class); + + private IotaAPIService service; + private String protocol, host, port; + + private IotaAPICoreProxy(final Builder builder) { + protocol = builder.protocol; + host = builder.host; + port = builder.port; + postConstruct(); + } + + protected static Response wrapCheckedException(final Call call) { + try { + final Response res = call.execute(); + if (res.code() == 400) { + throw new IllegalAccessError("400 " + res.errorBody().string()); + } else if (res.code() == 401) { + throw new IllegalAccessError("401 " + res.errorBody().string()); + } else if (res.code() == 500) { + throw new IllegalAccessError("500 " + res.errorBody().string()); + } + return res; + } catch (IOException e) { + log.error("Execution of the API call raised exception. IOTA Node not reachable?", e); + throw new IllegalStateException(e.getMessage()); + } + } + + private static final String env(String env, String def) { + final String value = System.getenv(env); + if (value == null) { + log.warn("Environment variable '{}' is not defined, and actual value has not been specified. " + + "Rolling back to default value: '{}'", env, def); + return def; + } + return value; + } + + private void postConstruct() { + + final String nodeUrl = protocol + "://" + host + ":" + port; + + final OkHttpClient client = new OkHttpClient.Builder() + .readTimeout(5000, TimeUnit.SECONDS) + .connectTimeout(5000, TimeUnit.SECONDS) + .build(); + + final Retrofit retrofit = new Retrofit.Builder() + .baseUrl(nodeUrl) + .addConverterFactory(GsonConverterFactory.create()) + .client(client) + .build(); + + service = retrofit.create(IotaAPIService.class); + + log.debug("Jota-API Java proxy pointing to node url: '{}'", nodeUrl); + } + + public GetNodeInfoResponse getNodeInfo() { + final Call res = service.getNodeInfo(IotaCommandRequest.createNodeInfoRequest()); + return wrapCheckedException(res).body(); + } + + public GetNeighborsResponse getNeighbors() { + final Call res = service.getNeighbors(IotaCommandRequest.createGetNeighborsRequest()); + return wrapCheckedException(res).body(); + } + + public AddNeighborsResponse addNeighbors(String... uris) { + final Call res = service.addNeighbors(IotaNeighborsRequest.createAddNeighborsRequest(uris)); + return wrapCheckedException(res).body(); + } + + public RemoveNeighborsResponse removeNeighbors(String... uris) { + final Call res = service.removeNeighbors(IotaNeighborsRequest.createRemoveNeighborsRequest(uris)); + return wrapCheckedException(res).body(); + } + + public GetTipsResponse getTips() { + final Call res = service.getTips(IotaCommandRequest.createGetTipsRequest()); + return wrapCheckedException(res).body(); + } + + public FindTransactionResponse findTransactions(String[] addresses, String[] tags, String[] approvees, String[] bundles) { + + final IotaFindTransactionsRequest findTransRequest = IotaFindTransactionsRequest + .createFindTransactionRequest() + .byAddresses(addresses) + .byTags(tags) + .byApprovees(approvees) + .byBundles(bundles); + + final Call res = service.findTransactions(findTransRequest); + return wrapCheckedException(res).body(); + } + + public FindTransactionResponse findTransactionsByAddresses(final String... addresses) { + return findTransactions(addresses, null, null, null); + } + + public FindTransactionResponse findTransactionsByBundles(final String... bundles) { + return findTransactions(null, null, null, bundles); + } + + public FindTransactionResponse findTransactionsByApprovees(final String... approvees) { + return findTransactions(null, null, approvees, null); + } + + public FindTransactionResponse findTransactionsByDigests(final String... digests) { + return findTransactions(null, digests, null, null); + } + + public GetInclusionStateResponse getInclusionStates(String[] transactions, String[] tips) { + final Call res = service.getInclusionStates(IotaGetInclusionStateRequest + .createGetInclusionStateRequest(transactions, tips)); + return wrapCheckedException(res).body(); + } + + public GetInclusionStateResponse getInclusionStates(Collection transactions, Collection tips) { + final Call res = service.getInclusionStates(IotaGetInclusionStateRequest + .createGetInclusionStateRequest(transactions, tips)); + return wrapCheckedException(res).body(); + } + + public GetTrytesResponse getTrytes(String... hashes) { + final Call res = service.getTrytes(IotaGetTrytesRequest.createGetTrytesRequest(hashes)); + return wrapCheckedException(res).body(); + } + + public GetTransactionsToApproveResponse getTransactionsToApprove(Integer depth) { + final Call res = service.getTransactionsToApprove(IotaGetTransactionsToApproveRequest.createIotaGetTransactionsToApproveRequest(depth)); + return wrapCheckedException(res).body(); + } + + public GetBalancesResponse getBalances(Integer threshold, String[] addresses) { + final Call res = service.getBalances(IotaGetBalancesRequest.createIotaGetBalancesRequest(threshold, addresses)); + return wrapCheckedException(res).body(); + } + + public GetBalancesResponse getBalances(Integer threshold, List addresses) { + return getBalances(threshold, addresses.toArray(new String[]{})); + } + + public InterruptAttachingToTangleResponse interruptAttachingToTangle() { + final Call res = service.interruptAttachingToTangle(IotaCommandRequest.createInterruptAttachToTangleRequest()); + return wrapCheckedException(res).body(); + } + + public GetAttachToTangleResponse attachToTangle(String trunkTransaction, String branchTransaction, Integer minWeightMagnitude, String... trytes) { + final Call res = service.attachToTangle(IotaAttachToTangleRequest.createAttachToTangleRequest(trunkTransaction, branchTransaction, minWeightMagnitude, trytes)); + return wrapCheckedException(res).body(); + } + + public StoreTransactionsResponse storeTransactions(String... trytes) { + final Call res = service.storeTransactions(IotaStoreTransactionsRequest.createStoreTransactionsRequest(trytes)); + return wrapCheckedException(res).body(); + } + + public BroadcastTransactionsResponse broadcastTransactions(String... trytes) { + final Call res = service.broadcastTransactions(IotaBroadcastTransactionRequest.createBroadcastTransactionsRequest(trytes)); + return wrapCheckedException(res).body(); + } + + public static class Builder { + + String protocol, host, port; + + public IotaAPICoreProxy build() { + + if (protocol == null || host == null || port == null) { + + // check properties files. + if (!checkPropertiesFiles()) { + + // last resort: best effort on enviroment variable, + // before assigning default values. + checkEnviromentVariables(); + } + } + + return new IotaAPICoreProxy(this); + } + + private boolean checkPropertiesFiles() { + + try { + + FileReader fileReader = new FileReader("node_config.properties"); + BufferedReader bufferedReader = new BufferedReader(fileReader); + + final Properties nodeConfig = new Properties(); + nodeConfig.load(bufferedReader); + + if (nodeConfig.getProperty("iota.node.protocol") != null) { + protocol = nodeConfig.getProperty("iota.node.protocol"); + } + + if (nodeConfig.getProperty("iota.node.host") != null) { + host = nodeConfig.getProperty("iota.node.host"); + } + + if (nodeConfig.getProperty("iota.node.port") != null) { + port = nodeConfig.getProperty("iota.node.port"); + } + + } catch (IOException e1) { + log.debug("node_config.properties not found. Rolling back for another solution..."); + } + return (port != null && protocol != null && host != null); + } + + private void checkEnviromentVariables() { + protocol = env("IOTA_NODE_PROTOCOL", "http"); + host = env("IOTA_NODE_HOST", "localhost"); + port = env("IOTA_NODE_PORT", "14265"); + } + + public Builder host(String host) { + this.host = host; + return this; + } + + public Builder port(String port) { + this.port = port; + return this; + } + + public Builder protocol(String protocol) { + this.protocol = protocol; + return this; + } + + } +} diff --git a/src/main/java/jota/dto/response/AbstractResponse.java b/src/main/java/jota/dto/response/AbstractResponse.java index cab9488..547bf65 100644 --- a/src/main/java/jota/dto/response/AbstractResponse.java +++ b/src/main/java/jota/dto/response/AbstractResponse.java @@ -7,9 +7,9 @@ import org.apache.commons.lang3.builder.ToStringStyle; public abstract class AbstractResponse { - private Integer duration; + private Long duration; - public Integer getDuration() { + public Long getDuration() { return duration; } @@ -27,4 +27,8 @@ public abstract class AbstractResponse { public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj, false); } + + public void setDuration(Long duration) { + this.duration = duration; + } } diff --git a/src/main/java/jota/dto/response/GetAttachToTangleResponse.java b/src/main/java/jota/dto/response/GetAttachToTangleResponse.java index 53eb98b..8b70851 100644 --- a/src/main/java/jota/dto/response/GetAttachToTangleResponse.java +++ b/src/main/java/jota/dto/response/GetAttachToTangleResponse.java @@ -7,4 +7,8 @@ public class GetAttachToTangleResponse extends AbstractResponse { public String[] getTrytes() { return trytes; } + + public GetAttachToTangleResponse(long duration) { + setDuration(duration); + } } diff --git a/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java b/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java index 493d063..189e72e 100644 --- a/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java +++ b/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java @@ -8,7 +8,7 @@ public class GetBalancesAndFormatResponse extends AbstractResponse { private List input; private long totalBalance; - + public List getInput() { return input; } @@ -16,19 +16,20 @@ public class GetBalancesAndFormatResponse extends AbstractResponse { public void setInput(List input) { this.input = input; } - + public long getTotalBalance() { return totalBalance; } - + public void setTotalBalance(long totalBalance) { this.totalBalance = totalBalance; } - public static GetBalancesAndFormatResponse create(List inputs, long totalBalance2) { + public static GetBalancesAndFormatResponse create(List inputs, long totalBalance2, long duration) { GetBalancesAndFormatResponse res = new GetBalancesAndFormatResponse(); res.setInput(inputs); res.setTotalBalance(totalBalance2); + res.setDuration(duration); return res; } } diff --git a/src/main/java/jota/dto/response/GetBundleResponse.java b/src/main/java/jota/dto/response/GetBundleResponse.java index eac6ed8..c3dfa1b 100644 --- a/src/main/java/jota/dto/response/GetBundleResponse.java +++ b/src/main/java/jota/dto/response/GetBundleResponse.java @@ -9,9 +9,10 @@ public class GetBundleResponse extends AbstractResponse { private List transactions = new ArrayList<>(); - public static GetBundleResponse create (List transactions){ + public static GetBundleResponse create(List transactions, long duration) { GetBundleResponse res = new GetBundleResponse(); res.transactions = transactions; + res.setDuration(duration); return res; } diff --git a/src/main/java/jota/dto/response/GetNewAddressResponse.java b/src/main/java/jota/dto/response/GetNewAddressResponse.java index 484e17e..42d2288 100644 --- a/src/main/java/jota/dto/response/GetNewAddressResponse.java +++ b/src/main/java/jota/dto/response/GetNewAddressResponse.java @@ -6,9 +6,10 @@ public class GetNewAddressResponse extends AbstractResponse { private List addresses; - public static GetNewAddressResponse create(List addresses) { + public static GetNewAddressResponse create(List addresses, long duration) { GetNewAddressResponse res = new GetNewAddressResponse(); res.addresses = addresses; + res.setDuration(duration); return res; } diff --git a/src/main/java/jota/dto/response/GetTransferResponse.java b/src/main/java/jota/dto/response/GetTransferResponse.java index 72b9cec..e98251e 100644 --- a/src/main/java/jota/dto/response/GetTransferResponse.java +++ b/src/main/java/jota/dto/response/GetTransferResponse.java @@ -9,7 +9,7 @@ public class GetTransferResponse extends AbstractResponse { private Bundle[] transferBundle; - public static GetTransferResponse create(Bundle[] transferBundle) { + public static GetTransferResponse create(Bundle[] transferBundle, long duration) { GetTransferResponse res = new GetTransferResponse(); res.transferBundle = transferBundle; return res; diff --git a/src/main/java/jota/dto/response/ReplayBundleResponse.java b/src/main/java/jota/dto/response/ReplayBundleResponse.java index f163d33..2c60c6c 100644 --- a/src/main/java/jota/dto/response/ReplayBundleResponse.java +++ b/src/main/java/jota/dto/response/ReplayBundleResponse.java @@ -7,9 +7,10 @@ public class ReplayBundleResponse extends AbstractResponse { private Boolean[] successfully; - public static ReplayBundleResponse create(Boolean[] successfully) { + public static ReplayBundleResponse create(Boolean[] successfully, long duration) { ReplayBundleResponse res = new ReplayBundleResponse(); res.successfully = successfully; + res.setDuration(duration); return res; } diff --git a/src/main/java/jota/dto/response/SendTransferResponse.java b/src/main/java/jota/dto/response/SendTransferResponse.java index 62e2a23..d31b295 100644 --- a/src/main/java/jota/dto/response/SendTransferResponse.java +++ b/src/main/java/jota/dto/response/SendTransferResponse.java @@ -7,9 +7,10 @@ public class SendTransferResponse extends AbstractResponse { private Boolean[] successfully; - public static SendTransferResponse create(Boolean[] successfully) { + public static SendTransferResponse create(Boolean[] successfully, long duration) { SendTransferResponse res = new SendTransferResponse(); res.successfully = successfully; + res.setDuration(duration); return res; } diff --git a/src/main/java/jota/dto/response/StoreTransactionsResponse.java b/src/main/java/jota/dto/response/StoreTransactionsResponse.java index 04128d2..af6c773 100644 --- a/src/main/java/jota/dto/response/StoreTransactionsResponse.java +++ b/src/main/java/jota/dto/response/StoreTransactionsResponse.java @@ -1,6 +1,8 @@ package jota.dto.response; public class StoreTransactionsResponse extends AbstractResponse { - // empty response + public StoreTransactionsResponse(long duration) { + setDuration(duration); + } } diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 9efd908..ad8ef4d 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -1,6 +1,6 @@ package jota.model; -import jota.pow.Curl; +import jota.pow.JCurl; import jota.utils.Converter; import java.util.ArrayList; @@ -9,7 +9,7 @@ import java.util.List; /** * Created by pinpong on 09.12.16. */ -public class Bundle { +public class Bundle implements Comparable { private List transactions; private int length; @@ -56,7 +56,7 @@ public class Bundle { public void finalize() { - Curl curl = new Curl(); + JCurl curl = new JCurl(); curl.reset(); for (int i = 0; i < this.getTransactions().size(); i++) { @@ -71,11 +71,11 @@ public class Bundle { int[] t = Converter.trits(this.getTransactions().get(i).getAddress() + Converter.trytes(valueTrits) + this.getTransactions().get(i).getTag() + Converter.trytes(timestampTrits) + Converter.trytes(currentIndexTrits) + Converter.trytes(lastIndexTrits)); - curl.absorb(t, 0, t.length); + curl.absorbb(t, 0, t.length); } int[] hash = new int[243]; - curl.squeeze(hash, 0, hash.length); + curl.squeezee(hash, 0, hash.length); String hashInTrytes = Converter.trytes(hash); for (int i = 0; i < this.getTransactions().size(); i++) { @@ -145,4 +145,12 @@ public class Bundle { return normalizedBundle; } + @Override + public int compareTo(Object o) { + if (Long.parseLong(this.getTransactions().get(0).getTimestamp()) < Long.parseLong(((Bundle) o).getTransactions().get(0).getTimestamp())) + return -1; + if (Long.parseLong(this.getTransactions().get(0).getTimestamp()) > Long.parseLong(((Bundle) o).getTransactions().get(0).getTimestamp())) + return 1; + return 0; + } } diff --git a/src/main/java/jota/pow/ICurl.java b/src/main/java/jota/pow/ICurl.java new file mode 100644 index 0000000..4c2b015 --- /dev/null +++ b/src/main/java/jota/pow/ICurl.java @@ -0,0 +1,15 @@ +package jota.pow; + +/** + * Created by Adrian on 07.01.2017. + */ +public interface ICurl { + public JCurl absorbb(final int[] trits, int offset, int length); + public JCurl absorbb(final int[] trits); + public int[] squeezee(final int[] trits, int offset, int length); + public int[] squeezee(final int[] trits); + public JCurl transform(); + public JCurl reset(); + public int[] getState(); + public void setState(int[] state); + } diff --git a/src/main/java/jota/pow/Curl.java b/src/main/java/jota/pow/JCurl.java similarity index 78% rename from src/main/java/jota/pow/Curl.java rename to src/main/java/jota/pow/JCurl.java index b804250..2b6a775 100644 --- a/src/main/java/jota/pow/Curl.java +++ b/src/main/java/jota/pow/JCurl.java @@ -3,9 +3,9 @@ package jota.pow; /** * (c) 2016 Come-from-Beyond *

- * Curl belongs to the sponge function family. + * JCurl belongs to the sponge function family. */ -public class Curl { +public class JCurl implements ICurl { public static final int HASH_LENGTH = 243; private static final int STATE_LENGTH = 3 * HASH_LENGTH; @@ -15,7 +15,7 @@ public class Curl { private int[] state = new int[STATE_LENGTH]; - public Curl absorb(final int[] trits, int offset, int length) { + public JCurl absorbb(final int[] trits, int offset, int length) { do { System.arraycopy(trits, offset, state, 0, length < HASH_LENGTH ? length : HASH_LENGTH); @@ -25,12 +25,14 @@ public class Curl { return this; } - - public Curl absorb(final int[] trits) { - return absorb(trits, 0, trits.length); + + + + public JCurl absorbb(final int[] trits) { + return absorbb(trits, 0, trits.length); } - public Curl transform() { + public JCurl transform() { final int[] scratchpad = new int[STATE_LENGTH]; int scratchpadIndex = 0; @@ -43,14 +45,14 @@ public class Curl { return this; } - public Curl reset() { + public JCurl reset() { for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) { state[stateIndex] = 0; } return this; } - public int[] squeeze(final int[] trits, int offset, int length) { + public int[] squeezee(final int[] trits, int offset, int length) { do { System.arraycopy(state, 0, trits, offset, length < HASH_LENGTH ? length : HASH_LENGTH); @@ -61,8 +63,8 @@ public class Curl { return state; } - public int[] squeeze(final int[] trits) { - return squeeze(trits, 0, trits.length); + public int[] squeezee(final int[] trits) { + return squeezee(trits, 0, trits.length); } public int[] getState() { diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 6cb46a4..79605e5 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -1,6 +1,6 @@ package jota.utils; -import jota.pow.Curl; +import jota.pow.JCurl; import org.apache.commons.lang3.StringUtils; /** @@ -41,7 +41,7 @@ public class Checksum { } public static String calculateChecksum(String address) { - Curl curl = new Curl(); + JCurl curl = new JCurl(); curl.reset(); curl.setState(Converter.copyTrits(address, curl.getState())); curl.transform(); diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index ce2d604..8872481 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -1,7 +1,7 @@ package jota.utils; import jota.model.Transaction; -import jota.pow.Curl; +import jota.pow.JCurl; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -264,12 +264,12 @@ public class Converter { int[] transactionTrits = Converter.trits(trytes); int[] hash = new int[243]; - final Curl curl = new Curl(); // we need a fluent Curl. + final JCurl curl = new JCurl(); // we need a fluent JCurl. // generate the correct transaction hash curl.reset(); - curl.absorb(transactionTrits, 0, transactionTrits.length); - curl.squeeze(hash, 0, hash.length); + curl.absorbb(transactionTrits, 0, transactionTrits.length); + curl.squeezee(hash, 0, hash.length); Transaction trx = new Transaction(); diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 9f5e144..6430b0d 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -2,8 +2,6 @@ package jota.utils; import java.util.*; -import jota.IotaAPIProxy; -import jota.dto.response.GetNewAddressResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/jota/utils/NamedThreadFactory.java b/src/main/java/jota/utils/NamedThreadFactory.java new file mode 100644 index 0000000..a6e3dab --- /dev/null +++ b/src/main/java/jota/utils/NamedThreadFactory.java @@ -0,0 +1,26 @@ +package jota.utils; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by Adrian on 15.01.2017. + */ +public class NamedThreadFactory implements ThreadFactory { + private final String baseName; + private final AtomicInteger threadNum = new AtomicInteger(0); + + public NamedThreadFactory(String baseName) { + this.baseName = baseName; + } + + @Override + public synchronized Thread newThread(Runnable r) { + Thread t = Executors.defaultThreadFactory().newThread(r); + + t.setName(baseName + "-" + threadNum.getAndIncrement()); + + return t; + } +} \ No newline at end of file diff --git a/src/main/java/jota/utils/Parallel.java b/src/main/java/jota/utils/Parallel.java new file mode 100644 index 0000000..1321cdf --- /dev/null +++ b/src/main/java/jota/utils/Parallel.java @@ -0,0 +1,45 @@ +package jota.utils; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Created by Adrian on 15.01.2017. + */ +public class Parallel { + private static final int NUM_CORES = Runtime.getRuntime().availableProcessors(); + + private static final ExecutorService forPool = Executors.newFixedThreadPool(NUM_CORES * 2, new NamedThreadFactory("Parallel.For")); + + public static void For(final Iterable elements, final Operation operation) { + try { + // invokeAll blocks for us until all submitted tasks in the call complete + forPool.invokeAll(createCallables(elements, operation)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public static Collection> createCallables(final Iterable elements, final Operation operation) { + List> callables = new LinkedList>(); + for (final T elem : elements) { + callables.add(new Callable() { + @Override + public Void call() { + operation.perform(elem); + return null; + } + }); + } + + return callables; + } + + public static interface Operation { + public void perform(T pParameter); + } +} \ No newline at end of file diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index b984a2b..9e48239 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -5,7 +5,7 @@ import java.util.Arrays; import java.util.List; import jota.model.Bundle; -import jota.pow.Curl; +import jota.pow.JCurl; public class Signing { @@ -21,12 +21,12 @@ public class Signing { } } - final Curl curl = new Curl(); + final JCurl curl = new JCurl(); curl.reset(); - curl.absorb(seed, 0, seed.length); - curl.squeeze(seed, 0, seed.length); + curl.absorbb(seed, 0, seed.length); + curl.squeezee(seed, 0, seed.length); curl.reset(); - curl.absorb(seed, 0, seed.length); + curl.absorbb(seed, 0, seed.length); final List key = new ArrayList<>(); int[] buffer = new int[seed.length]; @@ -35,7 +35,7 @@ public class Signing { while (length-- > 0) { for (int i = 0; i < 27; i++) { - curl.squeeze(buffer, offset, buffer.length); + curl.squeezee(buffer, offset, buffer.length); for (int j = 0; j < 243; j++) { key.add(buffer[j]); } @@ -58,7 +58,7 @@ public class Signing { int[] signatureFragment = keyFragment; int[] hash; - Curl curl = new Curl(); + JCurl curl = new JCurl(); for (int i = 0; i < 27; i++) { @@ -66,8 +66,8 @@ public class Signing { for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) { curl.reset() - .absorb(hash, 0, hash.length) - .squeeze(hash, 0, hash.length); + .absorbb(hash, 0, hash.length) + .squeezee(hash, 0, hash.length); } for (int j = 0; j < 243; j++) { @@ -79,16 +79,16 @@ public class Signing { } public static int[] address(int[] digests) { - final Curl curl = new Curl(); + final JCurl curl = new JCurl(); int[] address = new int[243]; curl.reset() - .absorb(digests) - .squeeze(address); + .absorbb(digests) + .squeezee(address); return address; } public static int[] digests(int[] key) { - final Curl curl = new Curl(); + final JCurl curl = new JCurl(); int[] digests = new int[(int) Math.floor(key.length / 6561) * 243]; int[] buffer = new int[243]; @@ -101,15 +101,15 @@ public class Signing { buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); for (int k = 0; k < 26; k++) { curl.reset() - .absorb(buffer) - .squeeze(buffer); + .absorbb(buffer) + .squeezee(buffer); } System.arraycopy(buffer, 0, keyFragment, j * 243, 243); } curl.reset(); - curl.absorb(keyFragment, 0, keyFragment.length); - curl.squeeze(buffer, 0, buffer.length); + curl.absorbb(keyFragment, 0, keyFragment.length); + curl.squeezee(buffer, 0, buffer.length); System.arraycopy(buffer, 0, digests, i * 243, 243); } @@ -120,21 +120,21 @@ public class Signing { int[] buffer = new int[243]; - Curl curl = new Curl().reset(); + JCurl curl = new JCurl().reset(); for (int i = 0; i < 27; i++) { buffer = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243); for (int j = normalizedBundleFragment[i] + 13; j-- > 0; ) { - Curl jCurl = new Curl(); + JCurl jCurl = new JCurl(); jCurl.reset(); - jCurl.absorb(buffer); - jCurl.squeeze(buffer); + jCurl.absorbb(buffer); + jCurl.squeezee(buffer); } - curl.absorb(buffer); + curl.absorbb(buffer); } - curl.squeeze(buffer); + curl.squeezee(buffer); return buffer; } diff --git a/src/main/java/jota/utils/StopWatch.java b/src/main/java/jota/utils/StopWatch.java new file mode 100644 index 0000000..699de6f --- /dev/null +++ b/src/main/java/jota/utils/StopWatch.java @@ -0,0 +1,71 @@ +package jota.utils; + +/** + * Created by Adrian on 15.01.2017. + */ +public class StopWatch { + private long startTime = 0; + private boolean running = false; + private long currentTime = 0; + + public StopWatch() { + this.startTime = System.currentTimeMillis(); + this.running = true; + } + + public void reStart() { + this.startTime = System.currentTimeMillis(); + this.running = true; + } + + public StopWatch stop() { + this.running = false; + return this; + } + + public void pause() { + this.running = false; + currentTime = System.currentTimeMillis() - startTime; + } + + public void resume() { + this.running = true; + this.startTime = System.currentTimeMillis() - currentTime; + } + + //elaspsed time in milliseconds + public long getElapsedTimeMili() { + long elapsed = 0; + if (running) { + elapsed = (System.currentTimeMillis() - startTime); + } + return elapsed; + } + + //elaspsed time in seconds + public long getElapsedTimeSecs() { + long elapsed = 0; + if (running) { + elapsed = (System.currentTimeMillis() - startTime) / 1000; + } + return elapsed; + } + + //elaspsed time in minutes + public long getElapsedTimeMin() { + long elapsed = 0; + if (running) { + elapsed = (System.currentTimeMillis() - startTime) / 1000 / 60; + } + return elapsed; + } + + //elaspsed time in hours + public long getElapsedTimeHour() { + long elapsed = 0; + if (running) { + elapsed = ((System.currentTimeMillis() - startTime) / 1000 / 3600); + } + return elapsed; + } +} diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPITest.java similarity index 50% rename from src/test/java/jota/IotaAPIProxyTest.java rename to src/test/java/jota/IotaAPITest.java index f467513..1a20fbf 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -6,6 +6,8 @@ import jota.dto.response.*; import jota.error.ArgumentException; import jota.error.InvalidBundleException; import jota.error.InvalidSignatureException; +import jota.model.Bundle; +import jota.model.Transaction; import jota.model.Transfer; import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; @@ -14,7 +16,6 @@ import org.junit.Before; import org.junit.Test; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static org.junit.Assert.assertThat; @@ -24,126 +25,59 @@ import static org.junit.Assert.assertThat; * * @author davassi */ -public class IotaAPIProxyTest { +public class IotaAPITest { private static Gson gson = new GsonBuilder().create(); private static final String TEST_SEED1 = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; - private static final String TEST_SEED2 = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; + private static final String TEST_SEED2 = "IHDEENZYITYVYSPKAURUZAQKGVJEREFDJMYTANNXXGPZ9GJWTEOJJ9IPMXOGZNQLSNMFDSQOTZAEETUEA"; private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTH"; private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; - private static final String TEST_HASH = "OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999"; + private static final String TEST_HASH = "CKZ9TYPLUWH9FUSYJMPIZBVHWFZXTZMVOJLC9KOICSTBBQWXYTOTMCVPSPMYNDONTXHRULRFAWD999999"; private static final String TEST_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; private static final String TEST_MILESTONE = "SMYMAKKPSUKCKDRUEYCGZJTYCZ9HHDMDUWBAPXARGURPQRHTAJDASRWMIDTPTBNDKDEFBUTBGGAFX9999"; private static final Integer TEST_MILESTONE_INDEX = 8059; private static final String TEST_MESSAGE = "JOTA"; private static final String TEST_TAG = "JOTASPAM9999999999999999999"; + private static final String[] TEST_ADDRESSES = new String[]{"KHJXD9XKXPIVQRGREUIPVJTMEY9L9MXZAAKBBRYNINTIOXWBRMNLLW9MLGAXMGQWDBZLCOGFCBNKTDLDC" + , "MQSAAEDPMKIAJPPGNLIHPQIVFGLHNEGG9JNMSHOQSVQHBQBMLNHY9WVRTCOYUOWOIJHBQXIQVFPDF9YRW" + , "RGYOHMECRNVPYYPIAKEWHSOLBYOQPRFRPOJGHUMEGLICCUIPTZEXLWDLLPBNRXONUTQGLSAJSLHRXFVQD" + , "FOJHXRVJRFMJTFDUWJYYZXCZIJXKQALLXMLKHZFDMHWTIBBXUKSNSUYJLKYRQBNXKRSUXZHDTPWXYD9YF" + , "B9YNPQO9EXID9RDEEGLCBJBYKBLWHTOQOZKTLJDFPJZOPKJJTNUYUVVTDJPBCBYIWGPSCMNRZFGFHFSXH" + , "NQEFOAFIYKZOUXDFQ9X9PHCNSDETRTJZINZ9EYGKU99QJLDSTSC9VTBAA9FHLNLNYQXWLTNPRJDWCGIPP" + , "CEGLBSXDJVXGKGOUHRGMAQDRVYXCQLXBKUDWKFFSIABCUYRATFPTEEDIFYGAASKFZYREHLBIXBTKP9KLC" + , "QLOXU9GIQXPPE9UUT9DSIDSIESRIXMTGZJMKLSJTNBCRELAVLWVJLUOLKGFCWAEPEQWZWPBV9YZJJEHUS" + , "XIRMYJSGQXMM9YPHJVVLAVGBBLEEMOOKHHBFWKEAXJFONZLNSLBCGPQEVDMMOGHFVRDSYTETIFOIVNCR9" + , "PDVVBYBXMHZKADPAYOKQNDPHRSWTHAWQ9GRVIBOIMZQTYCWEPCDWDVRSOUNASVBDLBOAMVLYEVVCMAM9N" + , "U9GAIAPUUQWJGISAZWPLHUELTZ9WSHWXS9JLPKOWHRRIVUKGWCTJMBULVMKTETTUNHZ9HWHBALUCJIROU" + , "VFPMKZLLMDUOEKNBEKQZPTNZJZF9UHRWSTHXLWQQ9OAXTZQHTZPAWNJNXKAZFSDFWKFQEKZIGJTLWQFLO" + , "IGHK9XIWOAYBZUEZHQLEXBPTXSWVANIOUZZCPNKUIJIJOJNAQCJWUJHYKCZOIKVAAHDGAWJZKLTPVQL9G" + , "LXQPWMNXSUZTEYNC9ZBBFHY9YWCCOVKBNIIOUSVXZJZMJKJFDUWGUVXYCHGKUHEEIDHSGEWFAHVJPRIJT" + , "AKFDX9PGGQLZUWRMZ9YBDF9CG9TWXCNALCSXSAWHFIMGXCSYCJLSWIQDGGVDRMNEKKECQEYAITGNLNJFQ" + , "YX9QSPYMSFVOW9UVZRDVOCPYYMUTDHCCPKHMXQSJQJYIXVCHILKW9GBYJTYGLIKBTRQMDCYBMLLNGSSIK" + , "DSYCJKNG9TAGJHSKZQ9XLKAKNSKJFZIPVEDGJFXRTFGENHZFQGXHWDBNXLLDABDMOYELPG9DIXSNJFWAR" + , "9ANNACZYLDDPZILLQBQG9YMG9XJUMTAENDFQ9HMSSEFWYOAXPJTUXBFTSAXDJPAO9FKTWBBSCSFMOUR9I" + , "WDTFFXHBHMFQQVXQLBFJFVVHVIIAVYM9PFAZCHMKET9ESMHIRHSMVDJBZTXPTAFVIASMSXRDCIYVWVQNO" + , "XCCPS9GMTSUB9DXPVKLTBDHOFX9PJMBYZQYQEXMRQDPGQPLWRGZGXODYJKGVFOHHYUJRCSXAIDGYSAWRB" + , "KVEBCGMEOPDPRCQBPIEMZTTXYBURGZVNH9PLHKPMM9D9FUKWIGLKZROGNSYIFHULLWQWXCNAW9HKKVIDC"}; - - private IotaAPIProxy proxy; + private IotaAPI iotaClient; @Before - public void createProxyInstance() { - proxy = new IotaAPIProxy.Builder().build(); + public void createApiClientInstance() { + iotaClient = new IotaAPI(); } @Test - public void shouldGetNodeInfo() { - GetNodeInfoResponse nodeInfo = proxy.getNodeInfo(); - assertThat(nodeInfo.getAppVersion(), IsNull.notNullValue()); - assertThat(nodeInfo.getAppName(), IsNull.notNullValue()); - assertThat(nodeInfo.getJreVersion(), IsNull.notNullValue()); - assertThat(nodeInfo.getJreAvailableProcessors(), IsNull.notNullValue()); - assertThat(nodeInfo.getJreFreeMemory(), IsNull.notNullValue()); - assertThat(nodeInfo.getJreMaxMemory(), IsNull.notNullValue()); - assertThat(nodeInfo.getJreTotalMemory(), IsNull.notNullValue()); - assertThat(nodeInfo.getLatestMilestone(), IsNull.notNullValue()); - assertThat(nodeInfo.getLatestMilestoneIndex(), IsNull.notNullValue()); - assertThat(nodeInfo.getLatestSolidSubtangleMilestone(), IsNull.notNullValue()); - assertThat(nodeInfo.getLatestSolidSubtangleMilestoneIndex(), IsNull.notNullValue()); - assertThat(nodeInfo.getNeighbors(), IsNull.notNullValue()); - assertThat(nodeInfo.getPacketsQueueSize(), IsNull.notNullValue()); - assertThat(nodeInfo.getTime(), IsNull.notNullValue()); - assertThat(nodeInfo.getTips(), IsNull.notNullValue()); - assertThat(nodeInfo.getTransactionsToRequest(), IsNull.notNullValue()); + public void shouldCreateIotaApiProxyInstanceWithDefaultValues() { + IotaAPI proxy = new IotaAPI(); + assertThat(proxy, IsNull.notNullValue()); } - @Test - public void shouldGetNeighbors() { - GetNeighborsResponse neighbors = proxy.getNeighbors(); - assertThat(neighbors.getNeighbors(), IsNull.notNullValue()); - } - - @Test - public void shouldAddNeighbors() { - AddNeighborsResponse res = proxy.addNeighbors("udp://8.8.8.8:14265"); - assertThat(res, IsNull.notNullValue()); - } - - @Test - public void shouldRemoveNeighbors() { - RemoveNeighborsResponse res = proxy.removeNeighbors("udp://8.8.8.8:14265"); - assertThat(res, IsNull.notNullValue()); - } - - @Test - public void shouldGetTips() { - GetTipsResponse tips = proxy.getTips(); - assertThat(tips, IsNull.notNullValue()); - } - - @Test - public void shouldFindTransactionsByAddresses() { - FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS_WITH_CHECKSUM); - System.err.println(gson.toJson(trans)); - assertThat(trans.getHashes(), IsNull.notNullValue()); - } - - @Test - public void shouldFindTransactionsByApprovees() { - FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{TEST_HASH}); - assertThat(trans.getHashes(), IsNull.notNullValue()); - } - - @Test - public void shouldFindTransactionsByBundles() { - FindTransactionResponse trans = proxy.findTransactionsByBundles(TEST_HASH); - assertThat(trans.getHashes(), IsNull.notNullValue()); - } - - @Test - public void shouldFindTransactionsByDigests() { - FindTransactionResponse trans = proxy.findTransactionsByDigests(TEST_HASH); - assertThat(trans.getHashes(), IsNull.notNullValue()); - } - - - // ### - - @Test - public void shouldGetTrytes() { - GetTrytesResponse res = proxy.getTrytes(TEST_HASH); - assertThat(res.getTrytes(), IsNull.notNullValue()); - - } - - @Test - public void shouldGetInclusionStates() { - GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); - assertThat(res.getStates(), IsNull.notNullValue()); - } - - @Test // very long execution - public void shouldGetTransactionsToApprove() { - GetTransactionsToApproveResponse res = proxy.getTransactionsToApprove(27); - assertThat(res.getTrunkTransaction(), IsNull.notNullValue()); - assertThat(res.getBranchTransaction(), IsNull.notNullValue()); - - } @Test public void shouldGetInputs() { - GetBalancesAndFormatResponse res = proxy.getInputs(TEST_SEED2, null, 0,0, 0); + GetBalancesAndFormatResponse res = iotaClient.getInputs(TEST_SEED1, null, 0, 0, 0); System.out.println(res); assertThat(res, IsNull.notNullValue()); assertThat(res.getTotalBalance(), IsNull.notNullValue()); @@ -151,26 +85,12 @@ public class IotaAPIProxyTest { } - @Test - public void shouldGetBalances() { - GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); - System.err.println(res); - assertThat(res.getBalances(), IsNull.notNullValue()); - assertThat(res.getMilestone(), IsNull.notNullValue()); - assertThat(res.getMilestoneIndex(), IsNull.notNullValue()); - - } - - @Test - public void shouldCreateIotaApiProxyInstanceWithDefaultValues() { - IotaAPIProxy proxy = new IotaAPIProxy.Builder().build(); - assertThat(proxy, IsNull.notNullValue()); - } @Test public void shouldCreateANewAddress() { - final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED1, 0, false, 1, false); - assertThat(res.getAddresses(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + final GetNewAddressResponse res = iotaClient.getNewAddress(TEST_SEED1, 0, false, 100, false); + assertThat(res.getAddresses().get(0), Is.is(TEST_ADDRESS_WITHOUT_CHECKSUM)); + System.out.println(new Gson().toJson(res)); } @Test @@ -178,46 +98,52 @@ public class IotaAPIProxyTest { List transfers = new ArrayList<>(); transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITH_CHECKSUM, 0, TEST_MESSAGE, TEST_TAG)); transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITH_CHECKSUM, 1, TEST_MESSAGE, TEST_TAG)); - List trytes = proxy.prepareTransfers(TEST_SEED1, transfers, null, null); + List trytes = iotaClient.prepareTransfers(TEST_SEED1, transfers, null, null); Assert.assertNotNull(trytes); assertThat(trytes.isEmpty(), Is.is(false)); } - @Test - public void shouldSendTrytes() { - proxy.sendTrytes(new String[]{TEST_TRYTES}, 18, 27); - } - @Test public void shouldGetLastInclusionState() { - GetInclusionStateResponse res = proxy.getLatestInclusion(new String[]{TEST_HASH}); + GetInclusionStateResponse res = iotaClient.getLatestInclusion(new String[]{TEST_HASH}); assertThat(res.getStates(), IsNull.notNullValue()); } @Test public void shouldFindTransactionObjects() { - assertThat(proxy.findTransactionObjects(new String[]{TEST_ADDRESS_WITH_CHECKSUM}), IsNull.notNullValue()); + List ftr = iotaClient.findTransactionObjects(TEST_ADDRESSES); + assertThat(ftr, IsNull.notNullValue()); } @Test public void shouldGetBundle() throws InvalidBundleException, ArgumentException, InvalidSignatureException { - assertThat(proxy.getBundle(TEST_HASH), IsNull.notNullValue()); + GetBundleResponse gbr = iotaClient.getBundle(TEST_HASH); + assertThat(gbr, IsNull.notNullValue()); } @Test public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { - GetTransferResponse gtr = proxy.getTransfers(TEST_SEED1, 0, 0, false); + GetTransferResponse gtr = iotaClient.getTransfers(TEST_SEED1, 0, 0, false); assertThat(gtr.getTransfers(), IsNull.notNullValue()); - GetTransferResponse gtr2 = proxy.getTransfers(TEST_SEED1, 0, 0, true); - assertThat(gtr2.getTransfers(), IsNull.notNullValue()); + for (Bundle test : gtr.getTransfers()) { + for (Transaction trx : test.getTransactions()) { + System.out.println(new Gson().toJson(trx)); + } + } + } + + @Test + public void shouldSendTrytes() { + iotaClient.sendTrytes(new String[]{TEST_TRYTES}, 9, 18); } @Test public void shouldSendTransfer() throws InvalidBundleException, ArgumentException, InvalidSignatureException { List transfers = new ArrayList<>(); - transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITHOUT_CHECKSUM, 0, "", TEST_TAG)); - SendTransferResponse str = proxy.sendTransfer(TEST_SEED1, 18, 27, transfers, null, null); + transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITHOUT_CHECKSUM, 0, "JUSTANOTHERTEST", TEST_TAG)); + SendTransferResponse str = iotaClient.sendTransfer(TEST_SEED2, 9, 18, transfers, null, null); assertThat(str.getSuccessfully(), IsNull.notNullValue()); } + } \ No newline at end of file diff --git a/src/test/java/jota/IotaCoreApiTest.java b/src/test/java/jota/IotaCoreApiTest.java new file mode 100644 index 0000000..66918d4 --- /dev/null +++ b/src/test/java/jota/IotaCoreApiTest.java @@ -0,0 +1,132 @@ +package jota; + +import com.google.gson.Gson; +import jota.dto.response.*; +import org.hamcrest.core.IsNull; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertThat; + +/** + * Created by Adrian on 15.01.2017. + */ +public class IotaCoreApiTest { + + private static final String TEST_BUNDLE = "XZKJUUMQOYUQFKMWQZNTFMSS9FKJLOEV9DXXXWPMQRTNCOUSUQNTBIJTVORLOQPLYZOTMLFRHYKMTGZZU"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_HASH = "OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999"; + private static IotaAPICoreProxy proxy; + + @Before + public void createProxyInstance() { + proxy = new IotaAPICoreProxy.Builder().build(); + } + + @Test + public void shouldGetNodeInfo() { + GetNodeInfoResponse nodeInfo = proxy.getNodeInfo(); + System.out.println(new Gson().toJson(nodeInfo)); + assertThat(nodeInfo.getAppVersion(), IsNull.notNullValue()); + assertThat(nodeInfo.getAppName(), IsNull.notNullValue()); + assertThat(nodeInfo.getJreVersion(), IsNull.notNullValue()); + assertThat(nodeInfo.getJreAvailableProcessors(), IsNull.notNullValue()); + assertThat(nodeInfo.getJreFreeMemory(), IsNull.notNullValue()); + assertThat(nodeInfo.getJreMaxMemory(), IsNull.notNullValue()); + assertThat(nodeInfo.getJreTotalMemory(), IsNull.notNullValue()); + assertThat(nodeInfo.getLatestMilestone(), IsNull.notNullValue()); + assertThat(nodeInfo.getLatestMilestoneIndex(), IsNull.notNullValue()); + assertThat(nodeInfo.getLatestSolidSubtangleMilestone(), IsNull.notNullValue()); + assertThat(nodeInfo.getLatestSolidSubtangleMilestoneIndex(), IsNull.notNullValue()); + assertThat(nodeInfo.getNeighbors(), IsNull.notNullValue()); + assertThat(nodeInfo.getPacketsQueueSize(), IsNull.notNullValue()); + assertThat(nodeInfo.getTime(), IsNull.notNullValue()); + assertThat(nodeInfo.getTips(), IsNull.notNullValue()); + assertThat(nodeInfo.getTransactionsToRequest(), IsNull.notNullValue()); + } + + @Test + public void shouldGetNeighbors() { + GetNeighborsResponse neighbors = proxy.getNeighbors(); + assertThat(neighbors.getNeighbors(), IsNull.notNullValue()); + } + + @Test + public void shouldAddNeighbors() { + AddNeighborsResponse res = proxy.addNeighbors("udp://8.8.8.8:14265"); + assertThat(res, IsNull.notNullValue()); + } + + @Test + public void shouldRemoveNeighbors() { + RemoveNeighborsResponse res = proxy.removeNeighbors("udp://8.8.8.8:14265"); + assertThat(res, IsNull.notNullValue()); + } + + @Test + public void shouldGetTips() { + GetTipsResponse tips = proxy.getTips(); + assertThat(tips, IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByAddresses() { + FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS_WITH_CHECKSUM); + assertThat(trans.getHashes(), IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByApprovees() { + FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{TEST_HASH}); + assertThat(trans.getHashes(), IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByBundles() { + FindTransactionResponse trans = proxy.findTransactionsByBundles(TEST_HASH); + assertThat(trans.getHashes(), IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactionsByDigests() { + FindTransactionResponse trans = proxy.findTransactionsByDigests(TEST_HASH); + assertThat(trans.getHashes(), IsNull.notNullValue()); + } + + @Test + public void shouldGetTrytes() { + GetTrytesResponse res = proxy.getTrytes(TEST_HASH); + assertThat(res.getTrytes(), IsNull.notNullValue()); + + } + + @Test + public void shouldGetInclusionStates() { + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); + assertThat(res.getStates(), IsNull.notNullValue()); + } + + @Test // very long execution + public void shouldGetTransactionsToApprove() { + GetTransactionsToApproveResponse res = proxy.getTransactionsToApprove(27); + assertThat(res.getTrunkTransaction(), IsNull.notNullValue()); + assertThat(res.getBranchTransaction(), IsNull.notNullValue()); + } + + @Test + public void shouldFindTransactions() { + String test = TEST_BUNDLE; + FindTransactionResponse resp = proxy.findTransactions(new String[]{test}, new String[]{test}, new String[]{test}, new String[]{test}); + System.out.println(new Gson().toJson(resp)); + } + + @Test + public void shouldGetBalances() { + GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); + System.err.println(res); + assertThat(res.getBalances(), IsNull.notNullValue()); + assertThat(res.getMilestone(), IsNull.notNullValue()); + assertThat(res.getMilestoneIndex(), IsNull.notNullValue()); + + } +} diff --git a/src/test/java/jota/IotaUnitConverterTest.java b/src/test/java/jota/IotaUnitConverterTest.java index 81da852..32976a6 100644 --- a/src/test/java/jota/IotaUnitConverterTest.java +++ b/src/test/java/jota/IotaUnitConverterTest.java @@ -48,11 +48,11 @@ public class IotaUnitConverterTest { @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"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1,false), "1 i"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000,false), "1 Ki"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000,false), "1 Mi" ); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000,false), "1 Gi" ); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000000L,false), "1 Ti"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000000000L,false), "1 Pi"); } }