From 11bb41a88965a8b722555a42555b1675dddbdd66 Mon Sep 17 00:00:00 2001 From: AZ Date: Tue, 27 Dec 2016 19:23:36 +0100 Subject: [PATCH] added getBundle, traverseBundle, bundleFromAddresses - pls test & verify --- src/main/java/jota/IotaAPIProxy.java | 396 +++++++++++++----- .../jota/dto/response/GetBundleResponse.java | 8 + .../java/jota/error/ArgumentException.java | 4 + .../jota/error/InvalidBundleException.java | 15 + .../jota/error/InvalidSignatureException.java | 10 + src/main/java/jota/model/Signature.java | 33 ++ src/main/java/jota/utils/Converter.java | 25 ++ src/main/java/jota/utils/IotaAPIUtils.java | 27 +- 8 files changed, 397 insertions(+), 121 deletions(-) create mode 100644 src/main/java/jota/error/InvalidBundleException.java create mode 100644 src/main/java/jota/error/InvalidSignatureException.java create mode 100644 src/main/java/jota/model/Signature.java diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 5c0c47d..f02a19c 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -2,13 +2,15 @@ package jota; import jota.dto.request.*; import jota.dto.response.*; -import jota.model.Bundle; -import jota.model.Input; -import jota.model.Transaction; -import jota.model.Transfer; +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 org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -26,13 +28,13 @@ import java.util.concurrent.TimeUnit; /** * IotaAPIProxy Builder. Usage: - * + *

* IotaApiProxy api = IotaApiProxy.Builder * .protocol("http") * .nodeAddress("localhost") * .port(12345) * .build(); - * + *

* GetNodeInfoResponse response = api.getNodeInfo(); * * @author davassi @@ -79,8 +81,8 @@ public class IotaAPIProxy { final String nodeUrl = protocol + "://" + host + ":" + port; final OkHttpClient client = new OkHttpClient.Builder() - .readTimeout(120, TimeUnit.SECONDS) - .connectTimeout(120, TimeUnit.SECONDS) + .readTimeout(5000, TimeUnit.SECONDS) + .connectTimeout(5000, TimeUnit.SECONDS) .build(); final Retrofit retrofit = new Retrofit.Builder() @@ -174,9 +176,9 @@ public class IotaAPIProxy { 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[] {})); + return getBalances(threshold, addresses.toArray(new String[]{})); } public InterruptAttachingToTangleResponse interruptAttachingToTangle() { @@ -215,7 +217,7 @@ public class IotaAPIProxy { public GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { final List allAddresses = new ArrayList<>(); - + // If total number of addresses to generate is supplied, simply generate // and return the list of all addresses if (total != 0) { @@ -227,10 +229,10 @@ public class IotaAPIProxy { // 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 String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); - + allAddresses.add(newAddress); if (response.getHashes().length == 0) { break; @@ -239,9 +241,9 @@ public class IotaAPIProxy { // If !returnAll return only the last address that was generated if (!returnAll) { - allAddresses.subList(0, allAddresses.size()-1).clear(); + allAddresses.subList(0, allAddresses.size() - 1).clear(); } - return GetNewAddressResponse.create(allAddresses); + return GetNewAddressResponse.create(allAddresses); } /* @@ -263,14 +265,101 @@ public class IotaAPIProxy { broadcastBundle getAccountData */ - + + /** + * @method getTransfers + * @param {string} seed + * @param {object} options + * @property {int} start Starting key index + * @property {int} end Ending key index + * @property {bool} inclusionStates returns confirmation status of all transactions + * @param {function} callback + * @returns {object} success + **/ + public Bundle[] getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + start = start != null ? 0 : start; + end = end == null ? null : end; + inclusionStates = inclusionStates != null ? inclusionStates : null; + + if (start > end || end > (start + 500)) { + throw new ArgumentException(); + } + + GetNewAddressResponse gnr = getNewAddress(seed, start, false, end == null ? end - start : end, true); + if (gnr != null && gnr.getAddresses() != null) { + return bundlesFromAddresses(gnr.getAddresses().toArray(new String[gnr.getAddresses().size()]), inclusionStates); + } + return null; + } + + public Bundle[] bundlesFromAddresses(String[] addresses, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException{ + + List trxs = findTransactionObjects(addresses); + // set of tail transactions + List tailTransactions = new ArrayList<>(); + List nonTailBundleHashes = new ArrayList<>(); + + for (Transaction trx : trxs) { + // Sort tail and nonTails + if (Long.parseLong(trx.getCurrentIndex()) == 0) { + tailTransactions.add(trx.getHash()); + } else { + nonTailBundleHashes.add(trx.getBundle()); + } + } + if (nonTailBundleHashes.isEmpty()) return null; + + List bundleObjects = findTransactionObjects(addresses); + for (Transaction trx : bundleObjects) { + // Sort tail and nonTails + if (Long.parseLong(trx.getCurrentIndex()) == 0) { + tailTransactions.add(trx.getHash()); + } + } + + List finalBundles = new ArrayList<>(); + String[] tailTxArray = tailTransactions.toArray(new String[tailTransactions.size()]); + + // If inclusionStates, get the confirmation status + // of the tail transactions, and thus the bundles + if (inclusionStates) { + GetInclusionStateResponse gisr = getLatestInclusion(tailTxArray); + if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) return null; + for (String trx : tailTxArray) { + Bundle gbr = getBundle(trx); + 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); + } + } + finalBundles.add(gbr); + } + } + } + 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; + } + }); + 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()); + } + return returnValue; + } + /** - * * @param trytes * @return a StoreTransactionsResponse */ - public StoreTransactionsResponse broadcastAndStore(final String ... trytes) { - + public StoreTransactionsResponse broadcastAndStore(final String... trytes) { + try { broadcastTransactions(trytes); } catch (Exception e) { @@ -279,30 +368,31 @@ public class IotaAPIProxy { } return storeTransactions(trytes); } - + /** * Facade method: Gets transactions to approve, attaches to Tangle, broadcasts and stores + * * @param {array} trytes - * @param {int} depth - * @param {int} minWeightMagnitude + * @param {int} depth + * @param {int} minWeightMagnitude * @return */ public List sendTrytes(final String[] trytes, final int minWeightMagnitude) { final GetTransactionsToApproveResponse txs = getTransactionsToApprove(minWeightMagnitude); - + // attach to tangle - do pow final GetAttachToTangleResponse res = attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); - + try { broadcastAndStore(res.getTrytes()); } catch (Exception e) { log.error("Impossible to sendTrytes, aborting.", e); throw new IllegalStateException("sendTrytes Illegal state Exception"); } - + //return Arrays.stream(res.getTrytes()).map(Converter::transactionObject).collect(Collectors.toList()); final List trx = new ArrayList<>(); - + for (final String tx : Arrays.asList(res.getTrytes())) { trx.add(Converter.transactionObject(tx)); } @@ -310,15 +400,15 @@ public class IotaAPIProxy { } /** - * Wrapper function for getTrytes and transactionObjects - * gets the trytes and transaction object from a list of transaction hashes - * - * @method getTransactionsObjects - * @param {array} hashes - * @return - * @returns {function} callback - * @returns {object} success - **/ + * Wrapper function for getTrytes and transactionObjects + * gets the trytes and transaction object from a list of transaction hashes + * + * @param {array} hashes + * @return + * @method getTransactionsObjects + * @returns {function} callback + * @returns {object} success + **/ public List getTransactionsObjects(String[] hashes) { if (!InputValidator.isArrayOfHashes(hashes)) { @@ -326,9 +416,9 @@ public class IotaAPIProxy { } final GetTrytesResponse trytesResponse = getTrytes(hashes); - + final List trxs = new ArrayList<>(); - + for (final String tryte : trytesResponse.getTrytes()) { trxs.add(Converter.transactionObject(tryte)); } @@ -356,18 +446,18 @@ public class IotaAPIProxy { } /** - * Prepares transfer by generating bundle, finding and signing inputs - * - * @method prepareTransfers - * @param {string} seed - * @param {object} transfers - * @param {object} options - * @property {array} inputs Inputs used for signing. Needs to have correct keyIndex and address value - * @property {string} address Remainder address - * @param {function} callback - * @return - * @returns {array} trytes Returns bundle trytes - **/ + * Prepares transfer by generating bundle, finding and signing inputs + * + * @param {string} seed + * @param {object} transfers + * @param {object} options + * @param {function} callback + * @return + * @method prepareTransfers + * @property {array} inputs Inputs used for signing. Needs to have correct keyIndex and address value + * @property {string} address Remainder address + * @returns {array} trytes Returns bundle trytes + **/ public List prepareTransfers(final String seed, final List transfers, String remainder, List inputs) { // Input validation of transfers object @@ -378,7 +468,7 @@ public class IotaAPIProxy { // Create a new bundle final Bundle bundle = new Bundle(); final List signatureFragments = new ArrayList<>(); - + int totalValue = 0; String tag; @@ -398,7 +488,7 @@ public class IotaAPIProxy { // While there is still a message, copy it while (!msgCopy.isEmpty()) { - + String fragment = StringUtils.substring(msgCopy, 0, 2187); msgCopy = StringUtils.substring(msgCopy, 2187, msgCopy.length()); @@ -454,7 +544,8 @@ public class IotaAPIProxy { String[] balances = resbalances.getBalances(); List confirmedInputs = new ArrayList<>(); - int totalBalance = 0; int i = 0; + int totalBalance = 0; + int i = 0; for (String balance : balances) { long thisBalance = Integer.parseInt(balance); totalBalance += thisBalance; @@ -495,23 +586,23 @@ public class IotaAPIProxy { List bundleTrytes = new ArrayList<>(); for (Transaction tx : trxb) { - bundleTrytes.add(jota.utils.IotaAPIUtils.transactionTrytes(tx)); + bundleTrytes.add(Converter.transactionTrytes(tx)); } return bundleTrytes; } } /** - * Gets the inputs of a seed - * - * @method getInputs - * @param {string} seed - * @param {object} options - * @property {int} start Starting key index - * @property {int} end Ending key index - * @property {int} threshold Min balance required - * @param {function} callback - **/ + * Gets the inputs of a seed + * + * @param {string} seed + * @param {object} options + * @param {function} callback + * @method getInputs + * @property {int} start Starting key index + * @property {int} end Ending key index + * @property {int} threshold Min balance required + **/ public GetBalancesAndFormatResponse getInputs(final String seed, final List balances, int start, int end, int threshold) { // validate the seed @@ -564,18 +655,19 @@ public class IotaAPIProxy { // If threshold defined, keep track of whether reached or not // else set default to true - boolean thresholdReached = threshold != 0 ? false : true; int i = -1; - + boolean thresholdReached = threshold != 0 ? false : true; + int i = -1; + List inputs = new ArrayList<>(); long totalBalance = 0; - + for (String address : addresses) { - + long balance = Long.parseLong(balances.get(++i)); - + if (balance > 0) { - final Input newEntry = new Input(address, balance, start+i); - + final Input newEntry = new Input(address, balance, start + i); + inputs.add(newEntry); // Increase totalBalance of all aggregated inputs totalBalance += balance; @@ -589,53 +681,121 @@ public class IotaAPIProxy { if (thresholdReached) { return GetBalancesAndFormatResponse.create(inputs, totalBalance); - } + } throw new IllegalStateException("Not enough balance"); } /** - * Gets the associated bundle transactions of a single transaction - * Does validation of signatures, total sum as well as bundle order + * Gets the associated bundle transactions of a single transaction + * Does validation of signatures, total sum as well as bundle order * - * @method getBundle - * @param {string} transaction Hash of a tail transaction - * @returns {list} bundle Transaction objects + * @param {string} transaction Hash of a tail transaction + * @method getBundle + * @returns {list} bundle Transaction objects **/ - public GetBundleResponse getBundle(String transaction) { - return null; //IotaAPIUtils.getBundle(transaction); + public Bundle getBundle(String transaction) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + + Bundle bundle = traverseBundle(transaction, null, null); + if (bundle == null) { + return null; + } + + long totalSum = 0; + int lastIndex = 0; + String bundleHash = bundle.getTransactions().get(0).getBundle(); + + Curl curl = new Curl(); + curl.reset(); + + List signaturesToValidate = new ArrayList<>(); + + for (int i = 0; i < bundle.getTransactions().size(); i++) { + Transaction trx = bundle.getTransactions().get(i); + Long bundleValue = Long.parseLong(trx.getValue()); + totalSum += bundleValue; + + if (i != Integer.parseInt(bundle.getTransactions().get(i).getCurrentIndex())) { + throw new ArgumentException("Invalid Bundle"); + } + + String trxTrytes = Converter.transactionTrytes(trx).substring(2187, 2187 + 162); + + // Absorb bundle hash + value + timestamp + lastIndex + currentIndex trytes. + curl.absorb(Converter.trits(trxTrytes)); + // Check if input transaction + if (bundleValue < 0) { + String address = trx.getAddress(); + Signature sig = new Signature(); + sig.setAddress(address); + sig.getSignatureFragments().add(trx.getSignatureFragments()); + + // Find the subsequent txs with the remaining signature fragment + for (int y = i; i < bundle.getTransactions().size() - 1; i++) { + Transaction newBundleTx = bundle.getTransactions().get(i + 1); + + // Check if new tx is part of the signature fragment + if (newBundleTx.getAddress().equals(address) && Long.parseLong(newBundleTx.getValue()) == 0) { + sig.getSignatureFragments().add(newBundleTx.getSignatureFragments()); + } + } + signaturesToValidate.add(sig); + } + } + + // Check for total sum, if not equal 0 return error + if (totalSum != 0) throw new InvalidBundleException("Invalid Bundle Sum"); + + int[] bundleFromTrxs = curl.squeeze(new int[243]); + String bundleFromTxString = Converter.trytes(bundleFromTrxs); + + // Check if bundle hash is the same as returned by tx object + if (!bundleFromTxString.equals(bundleHash)) throw new InvalidBundleException("Invalid Bundle Hash"); + // Last tx in the bundle should have currentIndex === lastIndex + if (!bundle.getTransactions().get(bundle.getLength() - 1).getCurrentIndex().equals(bundle.getTransactions().get(bundle.getLength() - 1).getLastIndex())) + throw new InvalidBundleException("Invalid Bundle"); + + // Validate the signatures + for (int i = 0; i < signaturesToValidate.size(); i++) { + + boolean isValidSignature = Signing.validateSignatures(signaturesToValidate.get(i).getAddress(), signaturesToValidate.get(i).getSignatureFragments().toArray(new String[signaturesToValidate.size()]), bundleHash); + + if (!isValidSignature) throw new InvalidSignatureException(); + } + + return bundle; } /** - * Replays a transfer by doing Proof of Work again + * Replays a transfer by doing Proof of Work again * - * @method replayBundle - * @param {string} tail - * @param {int} depth - * @param {int} minWeightMagnitude - * @param {function} callback - * @returns {object} analyzed Transaction objects + * @param {string} tail + * @param {int} depth + * @param {int} minWeightMagnitude + * @param {function} callback + * @method replayBundle + * @returns {object} analyzed Transaction objects **/ - public List replayTransfer(String transaction, int depth, int minWeightMagnitude) { + public List replayTransfer(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, InvalidSignatureException, ArgumentException { List bundleTrytes = new ArrayList<>(); - GetBundleResponse bundle = getBundle(transaction); + Bundle bundle = getBundle(transaction); for (Transaction element : bundle.getTransactions()) { - bundleTrytes.add(IotaAPIUtils.transactionTrytes(element)); + bundleTrytes.add(Converter.transactionTrytes(element)); } return sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), minWeightMagnitude); } /** - * Wrapper function for getNodeInfo and getInclusionStates + * Wrapper function for getNodeInfo and getInclusionStates * - * @method getLatestInclusion - * @param {array} hashes - * @returns {function} callback - * @returns {array} state + * @param {array} hashes + * @method getLatestInclusion + * @returns {function} callback + * @returns {array} state **/ public GetInclusionStateResponse getLatestInclusion(String[] hashes) { GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); @@ -648,11 +808,57 @@ public class IotaAPIProxy { public Transaction[] sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, Input[] inputs, String address) { - List trytes = prepareTransfers(seed, Arrays.asList(transactions), address, Arrays.asList(inputs)); + List trytes = prepareTransfers(seed, Arrays.asList(transactions), address, inputs == null ? null : Arrays.asList(inputs)); List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), minWeightMagnitude); return trxs.toArray(new Transaction[trxs.size()]); } + /** + * Basically traverse the Bundle by going down the trunkTransactions until + * the bundle hash of the transaction is no longer the same. In case the input + * transaction hash is not a tail, we return an error. + * + * @param {string} trunkTx Hash of a trunk or a tail transaction of a bundle + * @param {string} bundleHash + * @param {array} bundle List of bundles to be populated + * @method traverseBundle + * @returns {array} bundle Transaction objects + **/ + public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { + GetTrytesResponse gtr = getTrytes(trunkTx); + if (gtr != null & gtr.getTrytes().length != 0) { + Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]); + if (trx == null || trx.getBundle() == null) { + throw new ArgumentException("Invalid trytes, could not create object"); + } + // If first transaction to search is not a tail, return error + if (bundleHash == null && Integer.parseInt(trx.getCurrentIndex()) != 0) { + throw new ArgumentException("Invalid tail transaction supplied."); + } + // If no bundle hash, define it + if (bundleHash == null) { + bundleHash = trx.getBundle(); + } + // If different bundle hash, return with bundle + if (bundleHash != trx.getBundle()) { + return bundle; + } + // If only one bundle element, return + if (Integer.parseInt(trx.getLastIndex()) == 0 && Integer.parseInt(trx.getCurrentIndex()) == 0) { + return new Bundle(Arrays.asList(trx), 1); + } + // Define new trunkTransaction for search + trunkTx = trx.getTrunkTransaction(); + // Add transaction object to bundle + bundle.getTransactions().add(trx); + + // Continue traversing with new trunkTx + return traverseBundle(trunkTx, bundleHash, bundle); + } else { + return null; + } + } + public static class Builder { String protocol, host, port; diff --git a/src/main/java/jota/dto/response/GetBundleResponse.java b/src/main/java/jota/dto/response/GetBundleResponse.java index 278631f..34ffb89 100644 --- a/src/main/java/jota/dto/response/GetBundleResponse.java +++ b/src/main/java/jota/dto/response/GetBundleResponse.java @@ -7,6 +7,14 @@ import java.util.List; public class GetBundleResponse extends AbstractResponse { + public GetBundleResponse(){ + + } + + public GetBundleResponse(List trxs){ + this.transactions = trxs; + } + private List transactions = new ArrayList<>(); public List getTransactions() { diff --git a/src/main/java/jota/error/ArgumentException.java b/src/main/java/jota/error/ArgumentException.java index c3da421..075d90e 100644 --- a/src/main/java/jota/error/ArgumentException.java +++ b/src/main/java/jota/error/ArgumentException.java @@ -10,4 +10,8 @@ public class ArgumentException extends BaseException { public ArgumentException() { super("Wrong arguments passed to function"); } + + public ArgumentException(String msg) { + super(msg); + } } diff --git a/src/main/java/jota/error/InvalidBundleException.java b/src/main/java/jota/error/InvalidBundleException.java new file mode 100644 index 0000000..9f7877d --- /dev/null +++ b/src/main/java/jota/error/InvalidBundleException.java @@ -0,0 +1,15 @@ +package jota.error; + +/** + * Created by Adrian on 27.12.2016. + */ +public class InvalidBundleException extends BaseException { + + public InvalidBundleException(){ + super("Invalid Bundle"); + } + + public InvalidBundleException(String msg){ + super(msg); + } +} diff --git a/src/main/java/jota/error/InvalidSignatureException.java b/src/main/java/jota/error/InvalidSignatureException.java new file mode 100644 index 0000000..d8d5565 --- /dev/null +++ b/src/main/java/jota/error/InvalidSignatureException.java @@ -0,0 +1,10 @@ +package jota.error; + +/** + * Created by Adrian on 27.12.2016. + */ +public class InvalidSignatureException extends BaseException { + public InvalidSignatureException() { + super("Invalid Signatures!"); + } +} diff --git a/src/main/java/jota/model/Signature.java b/src/main/java/jota/model/Signature.java new file mode 100644 index 0000000..3e0a9ba --- /dev/null +++ b/src/main/java/jota/model/Signature.java @@ -0,0 +1,33 @@ +package jota.model; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Adrian on 27.12.2016. + */ +public class Signature { + + String address; + List signatureFragments; + + public Signature() { + this.signatureFragments = new ArrayList<>(); + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public List getSignatureFragments() { + return signatureFragments; + } + + public void setSignatureFragments(List signatureFragments) { + this.signatureFragments = signatureFragments; + } +} diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 5e76567..f2a10b9 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -206,6 +206,31 @@ public class Converter { } } } + + public static String transactionTrytes(Transaction trx) { + int[] valueTrits = Converter.trits(trx.getValue(), 81); + + int[] timestampTrits = Converter.trits(trx.getTimestamp(), 27); + + + int[] currentIndexTrits = Converter.trits(trx.getTimestamp(), 27); + + + int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex(), 27); + + + return trx.getSignatureFragments() + + trx.getAddress() + + Converter.trytes(valueTrits) + + trx.getTag() + + Converter.trytes(timestampTrits) + + Converter.trytes(currentIndexTrits) + + Converter.trytes(lastIndexTrits) + + trx.getBundle() + + trx.getTrunkTransaction() + + trx.getBranchTransaction() + + trx.getNonce(); + } public static Transaction transactionObject(final String trytes) { diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index d790e82..3116681 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -43,31 +43,6 @@ public class IotaAPIUtils { return address; } - public static String transactionTrytes(Transaction trx) { - int[] valueTrits = Converter.trits(trx.getValue(), 81); - - int[] timestampTrits = Converter.trits(trx.getTimestamp(), 27); - - - int[] currentIndexTrits = Converter.trits(trx.getTimestamp(), 27); - - - int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex(), 27); - - - return trx.getSignatureFragments() - + trx.getAddress() - + Converter.trytes(valueTrits) - + trx.getTag() - + Converter.trytes(timestampTrits) - + Converter.trytes(currentIndexTrits) - + Converter.trytes(lastIndexTrits) - + trx.getBundle() - + trx.getTrunkTransaction() - + trx.getBranchTransaction() - + trx.getNonce(); - } - public static List signInputsAndReturn(final String seed, final List inputs, final Bundle bundle, @@ -138,7 +113,7 @@ public class IotaAPIUtils { // Convert all bundle entries into trytes for (Transaction tx : bundle.getTransactions()) { - bundleTrytes.add(IotaAPIUtils.transactionTrytes(tx)); + bundleTrytes.add(Converter.transactionTrytes(tx)); } Collections.reverse(bundleTrytes); return bundleTrytes;