From 6b6066fe1edbfd6a94930ec6cd2ecdd23e4537e7 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 1 Dec 2016 21:07:29 +0100 Subject: [PATCH 001/111] implemented toTrytes and toStrings --- src/main/java/jota/utils/TrytesConverter.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/main/java/jota/utils/TrytesConverter.java diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java new file mode 100644 index 0000000..3f90cbd --- /dev/null +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -0,0 +1,92 @@ +package jota.utils; + +/** + * Created by pinpong on 01.12.16. + */ +public class TrytesConverter { + + private static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + /** + * Conversion of ascii encoded bytes to trytes. + * Input is a string (can be stringified JSON object), return value is Trytes + *

+ * How the conversion works: + * 2 Trytes === 1 Byte + * There are a total of 27 different tryte values: 9ABCDEFGHIJKLMNOPQRSTUVWXYZ + *

+ * 1. We get the decimal value of an individual ASCII character + * 2. From the decimal value, we then derive the two tryte values by basically calculating the tryte equivalent (e.g. 100 === 19 + 3 * 27) + * a. The first tryte value is the decimal value modulo 27 (27 trytes) + * b. The second value is the remainder (decimal value - first value), divided by 27 + * 3. The two values returned from Step 2. are then input as indices into the available values list ('9ABCDEFGHIJKLMNOPQRSTUVWXYZ') to get the correct tryte value + *

+ * EXAMPLES + * Lets say we want to convert the ASCII character "Z". + * 1. 'Z' has a decimal value of 90. + * 2. 90 can be represented as 9 + 3 * 27. To make it simpler: + * a. First value: 90 modulo 27 is 9. This is now our first value + * b. Second value: (90 - 9) / 27 is 3. This is our second value. + * 3. Our two values are now 9 and 3. To get the tryte value now we simply insert it as indices into '9ABCDEFGHIJKLMNOPQRSTUVWXYZ' + * a. The first tryte value is '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'[9] === "I" + * b. The second tryte value is '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'[3] === "C" + * Our tryte pair is "IC" + *

+ * RESULT: + * The ASCII char "Z" is represented as "IC" in trytes. + */ + + public static String toTrytes(String inputString) { + + String trytes = ""; + + for (int i = 0; i < inputString.length(); i++) { + + char asciiValue = inputString.charAt(i); + + // If not recognizable ASCII character, replace with space + if (asciiValue > 255) { + asciiValue = 32; + } + + int firstValue = asciiValue % 27; + int secondValue = (asciiValue - firstValue) / 27; + + String trytesValue = String.valueOf(TRYTE_ALPHABET.charAt(firstValue) + String.valueOf(TRYTE_ALPHABET.charAt(secondValue))); + + trytes += trytesValue; + } + + return trytes; + } + + /** + * Trytes to bytes + * Reverse operation from the byteToTrytes function in send.js + * 2 Trytes == 1 Byte + * We assume that the trytes are a JSON encoded object thus for our encoding: + * First character = { + * Last character = } + * Everything after that is 9's padding + */ + + public static String toString(String inputTrytes) { + + String string = ""; + + for (int i = 0; i < inputTrytes.length(); i += 2) { + // get a trytes pair + + int firstValue = TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i)); + int secondValue = TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i + 1)); + + int decimalValue = firstValue + secondValue * 27; + + String character = Character.toString((char) decimalValue); + + string += character; + } + + return string; + } +} From 67230b861aacb85459586f58f7e41ed0b8c9103f Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 1 Dec 2016 21:10:07 +0100 Subject: [PATCH 002/111] added TrytesConverterTest --- src/test/java/jota/TrytesConverterTest.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/java/jota/TrytesConverterTest.java diff --git a/src/test/java/jota/TrytesConverterTest.java b/src/test/java/jota/TrytesConverterTest.java new file mode 100644 index 0000000..7741cff --- /dev/null +++ b/src/test/java/jota/TrytesConverterTest.java @@ -0,0 +1,21 @@ +package jota; + +import jota.utils.TrytesConverter; +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 01.12.16. + */ +public class TrytesConverterTest { + + @Test + public void shouldConvertStringToTrytes() { + assertEquals(TrytesConverter.toTrytes("Z"), "IC"); + } + @Test + public void shouldConvertTrytesToString() { + assertEquals(TrytesConverter.toString("IC"), "Z"); + } + +} From 0ec801a581906948293a324b2138a00ccfcd1288 Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 2 Dec 2016 18:47:43 +0100 Subject: [PATCH 003/111] WIP --- node_config.properties | 2 +- .../response/AnalyzeTransactionResponse.java | 83 ++-------------- .../jota/dto/response/GetBundleResponse.java | 90 ++--------------- .../dto/response/GetNeighborsResponse.java | 33 ++----- .../dto/response/GetTransfersResponse.java | 43 ++------ src/main/java/jota/model/Neighbor.java | 36 +++++++ src/main/java/jota/model/Transaction.java | 99 +++++++++++++++++++ src/main/java/jota/model/Transfer.java | 50 ++++++++++ src/main/java/jota/utils/Checksum.java | 44 +++++++++ src/main/java/jota/utils/Constants.java | 13 +++ src/main/java/jota/utils/Converter.java | 7 +- src/main/java/jota/utils/InputValidator.java | 35 +++++++ src/main/java/jota/utils/TrytesConverter.java | 8 +- src/test/java/jota/ChecksumTest.java | 25 +++++ src/test/java/jota/InputValidatorTest.java | 29 ++++++ 15 files changed, 363 insertions(+), 234 deletions(-) create mode 100644 src/main/java/jota/model/Neighbor.java create mode 100644 src/main/java/jota/model/Transaction.java create mode 100644 src/main/java/jota/model/Transfer.java create mode 100644 src/main/java/jota/utils/Checksum.java create mode 100644 src/main/java/jota/utils/Constants.java create mode 100644 src/main/java/jota/utils/InputValidator.java create mode 100644 src/test/java/jota/ChecksumTest.java create mode 100644 src/test/java/jota/InputValidatorTest.java diff --git a/node_config.properties b/node_config.properties index f3c3793..e5e5a5a 100644 --- a/node_config.properties +++ b/node_config.properties @@ -1,5 +1,5 @@ iota.node.protocol=http #iota.node.host=138.68.126.141 -iota.node.host=127.0.0.1 +iota.node.host=node.iotawallet.info iota.node.port=14265 diff --git a/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java b/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java index fdb7059..53081ff 100644 --- a/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java +++ b/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java @@ -1,86 +1,15 @@ package jota.dto.response; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import jota.model.Transaction; + +import java.util.ArrayList; +import java.util.List; public class AnalyzeTransactionResponse extends AbstractResponse { - private Transactions[] transactions; + private List transactions = new ArrayList(); - public Transactions[] getTransactions() { + public List getTransactions() { return transactions; } - - static class Transactions { - private String signatureMessageChunk; - private String index; - private String approvalNonce; - private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; - private String address; - private String value; - private String bundle; - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); - } - - public String getValue() { - return value; - } - - public String getDigest() { - return digest; - } - - public String getTrunkTransaction() { - return trunkTransaction; - } - - public String getTimestamp() { - return timestamp; - } - - public String getSignatureNonce() { - return signatureNonce; - } - - public String getType() { - return type; - } - - public String getAddress() { - return address; - } - - public String getApprovalNonce() { - return approvalNonce; - } - - public String getBranchTransaction() { - return branchTransaction; - } - - public String getBundle() { - return bundle; - } - - public String getHash() { - return hash; - } - - public String getIndex() { - return index; - } - - public String getSignatureMessageChunk() { - return signatureMessageChunk; - } - } } diff --git a/src/main/java/jota/dto/response/GetBundleResponse.java b/src/main/java/jota/dto/response/GetBundleResponse.java index c508f78..278631f 100644 --- a/src/main/java/jota/dto/response/GetBundleResponse.java +++ b/src/main/java/jota/dto/response/GetBundleResponse.java @@ -1,93 +1,15 @@ package jota.dto.response; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import jota.model.Transaction; + +import java.util.ArrayList; +import java.util.List; public class GetBundleResponse extends AbstractResponse { - public Transactions[] transactions; + private List transactions = new ArrayList<>(); - private String warning; - - public String getWarning() { - return warning; - } - - public Transactions[] getTransactions() { + public List getTransactions() { return transactions; } - - public static class Transactions { - private String signatureMessageChunk; - private String index; - private String approvalNonce; - private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; - private String address; - private String value; - private String bundle; - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); - } - - public String getAddress() { - return address; - } - - public String getApprovalNonce() { - return approvalNonce; - } - - public String getBranchTransaction() { - return branchTransaction; - } - - public String getBundle() { - return bundle; - } - - public String getDigest() { - return digest; - } - - public String getHash() { - return hash; - } - - public String getIndex() { - return index; - } - - public String getSignatureMessageChunk() { - return signatureMessageChunk; - } - - public String getSignatureNonce() { - return signatureNonce; - } - - public String getTimestamp() { - return timestamp; - } - - public String getType() { - return type; - } - - public String getTrunkTransaction() { - return trunkTransaction; - } - - public String getValue() { - return value; - } - - } } diff --git a/src/main/java/jota/dto/response/GetNeighborsResponse.java b/src/main/java/jota/dto/response/GetNeighborsResponse.java index 550a546..3740307 100644 --- a/src/main/java/jota/dto/response/GetNeighborsResponse.java +++ b/src/main/java/jota/dto/response/GetNeighborsResponse.java @@ -1,34 +1,15 @@ package jota.dto.response; +import jota.model.Neighbor; + +import java.util.ArrayList; +import java.util.List; + public class GetNeighborsResponse extends AbstractResponse { - public Neighbors[] neighbors; + private List neighbors = new ArrayList<>(); - public Neighbors[] getNeighbors() { + public List getNeighbors() { return neighbors; } - - public static class Neighbors { - - private String address; - private Integer numberOfAllTransactions; - private Integer numberOfInvalidTransactions; - private Integer numberOfNewTransactions; - - public String getAddress() { - return address; - } - - public Integer getNumberOfAllTransactions() { - return numberOfAllTransactions; - } - - public Integer getNumberOfInvalidTransactions() { - return numberOfInvalidTransactions; - } - - public Integer getNumberOfNewTransactions() { - return numberOfNewTransactions; - } - } } diff --git a/src/main/java/jota/dto/response/GetTransfersResponse.java b/src/main/java/jota/dto/response/GetTransfersResponse.java index 4046ad4..441ccea 100644 --- a/src/main/java/jota/dto/response/GetTransfersResponse.java +++ b/src/main/java/jota/dto/response/GetTransfersResponse.java @@ -1,46 +1,15 @@ package jota.dto.response; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import jota.model.Transfer; + +import java.util.ArrayList; +import java.util.List; public class GetTransfersResponse extends AbstractResponse { - private Transfers[] transfers; + private List transfers = new ArrayList<>(); - public Transfers[] getTransfers() { + public List getTransfers() { return transfers; } - - public static class Transfers { - private String timestamp; - private String address; - private String hash; - private Integer persistence; - private long value; - - public String getAddress() { - return address; - } - - public String getHash() { - return hash; - } - - public Integer getPersistence() { - return persistence; - } - - public String getTimestamp() { - return timestamp; - } - - public long getValue() { - return value; - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); - } - } } diff --git a/src/main/java/jota/model/Neighbor.java b/src/main/java/jota/model/Neighbor.java new file mode 100644 index 0000000..2eee719 --- /dev/null +++ b/src/main/java/jota/model/Neighbor.java @@ -0,0 +1,36 @@ +package jota.model; + +/** + * Created by pinpong on 02.12.16. + */ +public class Neighbor { + + private String address; + private Integer numberOfAllTransactions; + private Integer numberOfInvalidTransactions; + private Integer numberOfNewTransactions; + + public Neighbor(String address, Integer numberOfAllTransactions, Integer numberOfInvalidTransactions, Integer numberOfNewTransactions) { + this.address = address; + this.numberOfAllTransactions = numberOfAllTransactions; + this.numberOfInvalidTransactions = numberOfInvalidTransactions; + this.numberOfNewTransactions = numberOfNewTransactions; + } + + public String getAddress() { + return address; + } + + public Integer getNumberOfAllTransactions() { + return numberOfAllTransactions; + } + + public Integer getNumberOfInvalidTransactions() { + return numberOfInvalidTransactions; + } + + public Integer getNumberOfNewTransactions() { + return numberOfNewTransactions; + } + +} diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java new file mode 100644 index 0000000..4cf5e89 --- /dev/null +++ b/src/main/java/jota/model/Transaction.java @@ -0,0 +1,99 @@ +package jota.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by pinpong on 02.12.16. + */ +public class Transaction { + + private String signatureMessageChunk; + private String index; + private String approvalNonce; + private String hash; + private String digest; + private String type; + private String timestamp; + private String trunkTransaction; + private String branchTransaction; + private String signatureNonce; + private String address; + private String value; + private String bundle; + + public Transaction(String signatureMessageChunk, String index, String approvalNonce, String hash, String digest, String type, String timestamp, String trunkTransaction, String branchTransaction, String signatureNonce, String address, String value, String bundle) { + + this.hash = hash; + this.type = type; + this.signatureMessageChunk = signatureMessageChunk; + this.digest = digest; + this.address = address; + this.value = value; + this.timestamp = timestamp; + this.index = index; + this.bundle = bundle; + this.signatureNonce = signatureNonce; + this.approvalNonce = approvalNonce; + this.trunkTransaction = trunkTransaction; + this.branchTransaction = branchTransaction; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getValue() { + return value; + } + + public String getDigest() { + return digest; + } + + public String getTrunkTransaction() { + return trunkTransaction; + } + + public String getTimestamp() { + return timestamp; + } + + public String getSignatureNonce() { + return signatureNonce; + } + + public String getType() { + return type; + } + + public String getAddress() { + return address; + } + + public String getApprovalNonce() { + return approvalNonce; + } + + public String getBranchTransaction() { + return branchTransaction; + } + + public String getBundle() { + return bundle; + } + + public String getHash() { + return hash; + } + + public String getIndex() { + return index; + } + + public String getSignatureMessageChunk() { + return signatureMessageChunk; + } + +} diff --git a/src/main/java/jota/model/Transfer.java b/src/main/java/jota/model/Transfer.java new file mode 100644 index 0000000..fa149ee --- /dev/null +++ b/src/main/java/jota/model/Transfer.java @@ -0,0 +1,50 @@ +package jota.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by pinpong on 02.12.16. + */ +public class Transfer { + + private String timestamp; + private String address; + private String hash; + private Integer persistence; + private long value; + + public Transfer(String timestamp, String address, String hash, Integer persistence, long value) { + + this.timestamp = timestamp; + this.address = address; + this.hash = hash; + this.persistence = persistence; + this.value = value; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getAddress() { + return address; + } + + public String getHash() { + return hash; + } + + public Integer getPersistence() { + return persistence; + } + + public String getTimestamp() { + return timestamp; + } + + public long getValue() { + return value; + } +} diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java new file mode 100644 index 0000000..0a303db --- /dev/null +++ b/src/main/java/jota/utils/Checksum.java @@ -0,0 +1,44 @@ +package jota.utils; + +import org.apache.commons.lang3.NotImplementedException; + +/** + * Created by pinpong on 02.12.16. + */ +public class Checksum { + + public static String addChecksum(String address) { + + InputValidator.checkAddress(address); + String addressWithChecksum = address; + addressWithChecksum += calculateChecksum(address); + return addressWithChecksum; + } + + public static String removeChecksum(String addressWithChecksum) { + if (isAddressWithChecksum(addressWithChecksum)) { + return getAddress(addressWithChecksum); + } + throw new RuntimeException("Invalid address: " + addressWithChecksum); + } + + private static String getAddress(String addressWithChecksum) { + return addressWithChecksum.substring(0, Constants.addressLengthWithoutChecksum); + } + + public static boolean isValidChecksum(String addressWithChecksum) { + String addressWithoutChecksum = removeChecksum(addressWithChecksum); + String adressWithRecalculateChecksum = calculateChecksum(addressWithoutChecksum); + + return adressWithRecalculateChecksum.equals(addressWithChecksum); + } + + private static boolean isAddressWithChecksum(String addressWithChecksum) { + return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.addressLengthWithChecksum; + } + + private static String calculateChecksum(String address) { + // TODO + throw new NotImplementedException(address); + } +} diff --git a/src/main/java/jota/utils/Constants.java b/src/main/java/jota/utils/Constants.java new file mode 100644 index 0000000..997b296 --- /dev/null +++ b/src/main/java/jota/utils/Constants.java @@ -0,0 +1,13 @@ +package jota.utils; + +/** + * Created by pinpong on 02.12.16. + */ +public class Constants { + + public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public static int addressLengthWithoutChecksum = 81; + public static int addressLengthWithChecksum = 90; + +} diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index be5313f..b9cccbd 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -9,7 +9,6 @@ public class Converter { public static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; public static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; - public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; @@ -63,7 +62,7 @@ public class Converter { final int[] trits = new int[trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE]; for (int i = 0; i < trytes.length(); i++) { - System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); + System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); } return trits; @@ -100,9 +99,9 @@ public class Converter { int j = trits[offset + i * 3] + trits[offset + i * 3 + 1] * 3 + trits[offset + i * 3 + 2] * 9; if (j < 0) { - j += TRYTE_ALPHABET.length(); + j += Constants.TRYTE_ALPHABET.length(); } - trytes.append(TRYTE_ALPHABET.charAt(j)); + trytes.append(Constants.TRYTE_ALPHABET.charAt(j)); } return trytes.toString(); } diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java new file mode 100644 index 0000000..327812a --- /dev/null +++ b/src/main/java/jota/utils/InputValidator.java @@ -0,0 +1,35 @@ +package jota.utils; + +import jdk.nashorn.internal.runtime.regexp.joni.Regex; +import jota.model.Transfer; +import org.apache.commons.lang3.NotImplementedException; + +import java.util.Arrays; + +/** + * Created by pinpong on 02.12.16. + */ +public class InputValidator { + + public static boolean isAddress(String address) { + // TODO: In the future check checksum + // Check if address with checksum + return (address.length() == Constants.addressLengthWithoutChecksum || + address.length() == Constants.addressLengthWithChecksum) && isTrytes(address, address.length()); + } + + + public static boolean checkAddress(String address) { + if (!isAddress(address)) + throw new RuntimeException("Invalid address: " + address); + return true; + } + + public static boolean isTrytes(String trytes, int length) { + + // If no length specified, just validate the trytes + + Regex regexTrytes = new Regex("^[9A-Z]{" + (length == 0 ? "0," : length) + "}$"); + return trytes.matches(regexTrytes.toString()); + } +} diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java index 3f90cbd..4751b4a 100644 --- a/src/main/java/jota/utils/TrytesConverter.java +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -5,8 +5,6 @@ package jota.utils; */ public class TrytesConverter { - private static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - /** * Conversion of ascii encoded bytes to trytes. * Input is a string (can be stringified JSON object), return value is Trytes @@ -52,7 +50,7 @@ public class TrytesConverter { int firstValue = asciiValue % 27; int secondValue = (asciiValue - firstValue) / 27; - String trytesValue = String.valueOf(TRYTE_ALPHABET.charAt(firstValue) + String.valueOf(TRYTE_ALPHABET.charAt(secondValue))); + String trytesValue = String.valueOf(Constants.TRYTE_ALPHABET.charAt(firstValue) + String.valueOf(Constants.TRYTE_ALPHABET.charAt(secondValue))); trytes += trytesValue; } @@ -77,8 +75,8 @@ public class TrytesConverter { for (int i = 0; i < inputTrytes.length(); i += 2) { // get a trytes pair - int firstValue = TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i)); - int secondValue = TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i + 1)); + int firstValue = Constants.TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i)); + int secondValue = Constants.TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i + 1)); int decimalValue = firstValue + secondValue * 27; diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java new file mode 100644 index 0000000..d67afef --- /dev/null +++ b/src/test/java/jota/ChecksumTest.java @@ -0,0 +1,25 @@ +package jota; + +import jota.utils.Checksum; +import jota.utils.InputValidator; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 02.12.16. + */ +public class ChecksumTest { + + private static final String TEST_ADDRESS = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + + @Test + public void shouldAddChecksum() { + assertEquals(Checksum.addChecksum(TEST_ADDRESS), true); + } + + @Test + public void shouldRemoveChecksum() { + assertEquals(Checksum.addChecksum(TEST_ADDRESS), Checksum.isValidChecksum(Checksum.addChecksum(TEST_ADDRESS))); + } +} diff --git a/src/test/java/jota/InputValidatorTest.java b/src/test/java/jota/InputValidatorTest.java new file mode 100644 index 0000000..2ee0a10 --- /dev/null +++ b/src/test/java/jota/InputValidatorTest.java @@ -0,0 +1,29 @@ +package jota; + +import jota.utils.InputValidator; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 02.12.16. + */ +public class InputValidatorTest { + + private static final String TEST_ADDRESS = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + + @Test + public void shouldIsAddress() { + assertEquals(InputValidator.isAddress(TEST_ADDRESS), true); + } + + @Test + public void shouldCheckAddress() { + assertEquals(InputValidator.checkAddress(TEST_ADDRESS), true); + } + + @Test + public void shouldIsTrytes() { + assertEquals(InputValidator.isTrytes(TEST_ADDRESS, TEST_ADDRESS.length()), true); + } +} From 144ae811be41f947dcb903e043c321cbdd9d6db0 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 2 Dec 2016 19:29:11 +0100 Subject: [PATCH 004/111] added checksum calculation, pls review --- src/main/java/jota/utils/Checksum.java | 8 ++++++-- src/main/java/jota/utils/Converter.java | 10 ++++++++++ src/main/java/jota/utils/Curl.java | 5 +++-- src/main/java/jota/utils/InputValidator.java | 11 +---------- src/test/java/jota/ChecksumTest.java | 7 ++++--- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 0a303db..39d620f 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -38,7 +38,11 @@ public class Checksum { } private static String calculateChecksum(String address) { - // TODO - throw new NotImplementedException(address); + Curl curl = new Curl(); + curl.reset(); + curl.setState(Converter.copyTrits(address, curl.getState())); + curl.transform(); + String checksum = Converter.trytes(curl.getState()).substring(0, 9); + return checksum; } } diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index b9cccbd..a43388f 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -91,6 +91,16 @@ public class Converter { } } + public static int[] copyTrits(final String input, final int[] destination) { + for (int i = 0; i < input.length(); i++) { + int index = Constants.TRYTE_ALPHABET.indexOf(input.charAt(i)); + destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS [index][0]; + destination[i * 3 + 1] = TRYTE_TO_TRITS_MAPPINGS[index][1]; + destination[i * 3 + 2] = TRYTE_TO_TRITS_MAPPINGS[index][2]; + } + return destination; + } + public static String trytes(final int[] trits, final int offset, final int size) { StringBuilder trytes = new StringBuilder(); diff --git a/src/main/java/jota/utils/Curl.java b/src/main/java/jota/utils/Curl.java index b07236f..2c296e8 100644 --- a/src/main/java/jota/utils/Curl.java +++ b/src/main/java/jota/utils/Curl.java @@ -13,7 +13,7 @@ public class Curl { private static final int NUMBER_OF_ROUNDS = 27; private static final int[] TRUTH_TABLE = {1, 0, -1, 1, -1, 0, -1, 1, 0}; - private final int[] state = new int[STATE_LENGTH]; + private int[] state = new int[STATE_LENGTH]; public void absorb(final int[] trits, int offset, int length) { @@ -35,7 +35,7 @@ public class Curl { return state; } - private void transform() { + public void transform() { final int[] scratchpad = new int[STATE_LENGTH]; int scratchpadIndex = 0; @@ -56,4 +56,5 @@ public class Curl { public int[] getState() { return state; } + public void setState(int[] state) { this.state = state; } } diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 327812a..9ce67b7 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -1,11 +1,5 @@ package jota.utils; -import jdk.nashorn.internal.runtime.regexp.joni.Regex; -import jota.model.Transfer; -import org.apache.commons.lang3.NotImplementedException; - -import java.util.Arrays; - /** * Created by pinpong on 02.12.16. */ @@ -26,10 +20,7 @@ public class InputValidator { } public static boolean isTrytes(String trytes, int length) { - // If no length specified, just validate the trytes - - Regex regexTrytes = new Regex("^[9A-Z]{" + (length == 0 ? "0," : length) + "}$"); - return trytes.matches(regexTrytes.toString()); + return trytes.matches("^[9A-Z]{" + (length == 0 ? "0," : length) + "}$"); } } diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index d67afef..e56644e 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -11,15 +11,16 @@ import static org.junit.Assert.assertEquals; */ public class ChecksumTest { - private static final String TEST_ADDRESS = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTMLSDUKRPBM"; @Test public void shouldAddChecksum() { - assertEquals(Checksum.addChecksum(TEST_ADDRESS), true); + assertEquals(Checksum.addChecksum(TEST_ADDRESS_WITHOUT_CHECKSUM), TEST_ADDRESS_WITH_CHECKSUM); } @Test public void shouldRemoveChecksum() { - assertEquals(Checksum.addChecksum(TEST_ADDRESS), Checksum.isValidChecksum(Checksum.addChecksum(TEST_ADDRESS))); + assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); } } From 1a3bb711cdc32041894eced85dea0d531e17d937 Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 2 Dec 2016 21:49:10 +0100 Subject: [PATCH 005/111] updated checksum --- src/main/java/jota/utils/Checksum.java | 12 ++++-------- src/test/java/jota/ChecksumTest.java | 10 +++++++--- src/test/java/jota/InputValidatorTest.java | 9 +++++---- src/test/java/jota/IotaAPIProxyTest.java | 8 ++++---- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 39d620f..5b99ffa 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -1,14 +1,11 @@ package jota.utils; -import org.apache.commons.lang3.NotImplementedException; - /** * Created by pinpong on 02.12.16. */ public class Checksum { public static String addChecksum(String address) { - InputValidator.checkAddress(address); String addressWithChecksum = address; addressWithChecksum += calculateChecksum(address); @@ -28,21 +25,20 @@ public class Checksum { public static boolean isValidChecksum(String addressWithChecksum) { String addressWithoutChecksum = removeChecksum(addressWithChecksum); - String adressWithRecalculateChecksum = calculateChecksum(addressWithoutChecksum); + String addressWithRecalculateChecksum = calculateChecksum(addressWithoutChecksum); - return adressWithRecalculateChecksum.equals(addressWithChecksum); + return addressWithRecalculateChecksum.equals(addressWithChecksum); } private static boolean isAddressWithChecksum(String addressWithChecksum) { return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.addressLengthWithChecksum; } - private static String calculateChecksum(String address) { + public static String calculateChecksum(String address) { Curl curl = new Curl(); curl.reset(); curl.setState(Converter.copyTrits(address, curl.getState())); curl.transform(); - String checksum = Converter.trytes(curl.getState()).substring(0, 9); - return checksum; + return Converter.trytes(curl.getState()).substring(0, 9); } } diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index e56644e..1ff7a87 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -1,7 +1,6 @@ package jota; import jota.utils.Checksum; -import jota.utils.InputValidator; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -11,8 +10,8 @@ import static org.junit.Assert.assertEquals; */ public class ChecksumTest { - private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; - private static final String TEST_ADDRESS_WITH_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTMLSDUKRPBM"; + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; @Test public void shouldAddChecksum() { @@ -23,4 +22,9 @@ public class ChecksumTest { public void shouldRemoveChecksum() { assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); } + + @Test + public void shouldIsValidChecksum() { + assertEquals(Checksum.isValidChecksum(TEST_ADDRESS_WITH_CHECKSUM), true); + } } diff --git a/src/test/java/jota/InputValidatorTest.java b/src/test/java/jota/InputValidatorTest.java index 2ee0a10..8507b23 100644 --- a/src/test/java/jota/InputValidatorTest.java +++ b/src/test/java/jota/InputValidatorTest.java @@ -10,20 +10,21 @@ import static org.junit.Assert.assertEquals; */ public class InputValidatorTest { - private static final String TEST_ADDRESS = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; @Test public void shouldIsAddress() { - assertEquals(InputValidator.isAddress(TEST_ADDRESS), true); + assertEquals(InputValidator.isAddress(TEST_ADDRESS_WITHOUT_CHECKSUM), true); } @Test public void shouldCheckAddress() { - assertEquals(InputValidator.checkAddress(TEST_ADDRESS), true); + assertEquals(InputValidator.checkAddress(TEST_ADDRESS_WITHOUT_CHECKSUM), true); } @Test public void shouldIsTrytes() { - assertEquals(InputValidator.isTrytes(TEST_ADDRESS, TEST_ADDRESS.length()), true); + assertEquals(InputValidator.isTrytes(TEST_TRYTES, TEST_ADDRESS_WITHOUT_CHECKSUM.length()), true); } } diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 5a9d1e4..a1fdd8d 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -20,7 +20,8 @@ public class IotaAPIProxyTest { private static Gson gson = new GsonBuilder().create(); private static final String TEST_SEED = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; - private static final String TEST_ADDRESS = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; private static final String TEST_HASH = "OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999"; private static final String TEST_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; private static final String TEST_MILESTONE = "SMYMAKKPSUKCKDRUEYCGZJTYCZ9HHDMDUWBAPXARGURPQRHTAJDASRWMIDTPTBNDKDEFBUTBGGAFX9999"; @@ -65,7 +66,7 @@ public class IotaAPIProxyTest { @Test public void shouldFindTransactionsByAddresses() { - FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS); + FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS_WITH_CHECKSUM); System.err.println(gson.toJson(trans)); assertThat(trans, IsNull.notNullValue()); } @@ -99,7 +100,7 @@ public class IotaAPIProxyTest { @Test public void shouldGetInclusionStates() { - GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS}, + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"123"}); assertThat(res, IsNull.notNullValue()); } @@ -128,5 +129,4 @@ public class IotaAPIProxyTest { GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 2); System.err.println(res); } - } \ No newline at end of file From a77cadb2905da8349cb14630a7c90c6f0f8ba08a Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 2 Dec 2016 23:30:42 +0100 Subject: [PATCH 006/111] updated tests --- src/main/java/jota/utils/Checksum.java | 3 +-- src/main/java/jota/utils/InputValidator.java | 6 +----- src/test/java/jota/ChecksumTest.java | 3 +-- src/test/java/jota/InputValidatorTest.java | 2 +- src/test/java/jota/IotaAPIProxyTest.java | 2 +- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 5b99ffa..c184bce 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -25,8 +25,7 @@ public class Checksum { public static boolean isValidChecksum(String addressWithChecksum) { String addressWithoutChecksum = removeChecksum(addressWithChecksum); - String addressWithRecalculateChecksum = calculateChecksum(addressWithoutChecksum); - + String addressWithRecalculateChecksum = addressWithChecksum += calculateChecksum(addressWithoutChecksum); return addressWithRecalculateChecksum.equals(addressWithChecksum); } diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 9ce67b7..277a0ca 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -6,13 +6,10 @@ package jota.utils; public class InputValidator { public static boolean isAddress(String address) { - // TODO: In the future check checksum - // Check if address with checksum return (address.length() == Constants.addressLengthWithoutChecksum || address.length() == Constants.addressLengthWithChecksum) && isTrytes(address, address.length()); } - public static boolean checkAddress(String address) { if (!isAddress(address)) throw new RuntimeException("Invalid address: " + address); @@ -20,7 +17,6 @@ public class InputValidator { } public static boolean isTrytes(String trytes, int length) { - // If no length specified, just validate the trytes - return trytes.matches("^[9A-Z]{" + (length == 0 ? "0," : length) + "}$"); + return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } } diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index 1ff7a87..685aa62 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -10,9 +10,8 @@ import static org.junit.Assert.assertEquals; */ public class ChecksumTest { - private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTH"; private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; - @Test public void shouldAddChecksum() { assertEquals(Checksum.addChecksum(TEST_ADDRESS_WITHOUT_CHECKSUM), TEST_ADDRESS_WITH_CHECKSUM); diff --git a/src/test/java/jota/InputValidatorTest.java b/src/test/java/jota/InputValidatorTest.java index 8507b23..5f4795e 100644 --- a/src/test/java/jota/InputValidatorTest.java +++ b/src/test/java/jota/InputValidatorTest.java @@ -25,6 +25,6 @@ public class InputValidatorTest { @Test public void shouldIsTrytes() { - assertEquals(InputValidator.isTrytes(TEST_TRYTES, TEST_ADDRESS_WITHOUT_CHECKSUM.length()), true); + assertEquals(InputValidator.isTrytes(TEST_TRYTES, TEST_TRYTES.length()), true); } } diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index a1fdd8d..cb5dda3 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -20,7 +20,7 @@ public class IotaAPIProxyTest { private static Gson gson = new GsonBuilder().create(); private static final String TEST_SEED = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; - private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + 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_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; From 80ef2dcf7e2e03210305ef8a1c22fb1fb2eba31b Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 2 Dec 2016 23:50:10 +0100 Subject: [PATCH 007/111] fixed getnewaddress --- src/main/java/jota/utils/Checksum.java | 3 +-- src/main/java/jota/utils/IotaAPIUtils.java | 5 +++++ src/main/java/jota/utils/Signing.java | 18 ++++++++++------- src/test/java/jota/AddressGenerationTest.java | 20 +++++++++++++++++++ src/test/java/jota/ChecksumTest.java | 11 ++++------ 5 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 src/test/java/jota/AddressGenerationTest.java diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index c184bce..47e5567 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -15,8 +15,7 @@ public class Checksum { public static String removeChecksum(String addressWithChecksum) { if (isAddressWithChecksum(addressWithChecksum)) { return getAddress(addressWithChecksum); - } - throw new RuntimeException("Invalid address: " + addressWithChecksum); + } else return ""; } private static String getAddress(String addressWithChecksum) { diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index dd47181..5bcc294 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -18,8 +18,13 @@ public class IotaAPIUtils { public static GetNewAddressResponse getNewAddress(final String seed, final int index) { final int[] key = Signing.key(Converter.trits(seed), index, 2); + System.out.println("Length = "+ key.length ); final int[] digests = Signing.digests(key); + System.out.println("Length = "+ digests.length ); + final int[] addressTrits = Signing.address(digests); + System.out.println("Length = "+ addressTrits.length ); + final String address = Converter.trytes(addressTrits); return GetNewAddressResponse.create(address); diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 639a006..3cff61c 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -21,8 +21,10 @@ public class Signing { } Curl curl = new Curl(); - //curl.absorb(subseed, state); - //curl.squeeze(subseed, state); + curl.reset(); + curl.absorb(subseed, 0, subseed.length); + curl.squeeze(subseed, 0, subseed.length); + curl.reset(); curl.absorb(subseed, 0, subseed.length); List key = new ArrayList<>(); @@ -33,7 +35,7 @@ public class Signing { for (int i = 0; i < 27; i++) { - curl.squeeze(buffer, 0, buffer.length); + curl.squeeze(buffer, offset, buffer.length); for (int j = 0; j < 243; j++) { key.add(buffer[j]); } @@ -54,8 +56,8 @@ public class Signing { public static int[] digests(int[] key) { final Curl curl = new Curl(); - int[] digests = new int[key.length]; - int[] buffer = new int[key.length]; + int[] digests = new int[(int) Math.floor(key.length / 6561) * 243]; + int[] buffer = new int[243]; for (int i = 0; i < Math.floor(key.length / 6561); i++) { int[] keyFragment = Arrays.copyOfRange(key, i * 6561, (i + 1) * 6561); @@ -64,7 +66,7 @@ public class Signing { buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); for (int k = 0; k < 26; k++) { - + curl.reset(); curl.absorb(buffer, 0, buffer.length); curl.squeeze(buffer, 0, buffer.length); } @@ -74,6 +76,7 @@ public class Signing { } } + curl.reset(); curl.absorb(keyFragment, 0, keyFragment.length); curl.squeeze(buffer, 0, buffer.length); @@ -86,7 +89,8 @@ public class Signing { public static int[] address(int[] digests) { final Curl curl = new Curl(); - int[] address = new int[digests.length]; + int[] address = new int[243]; + curl.reset(); curl.absorb(digests, 0, digests.length); curl.squeeze(address, 0, address.length); return address; diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java new file mode 100644 index 0000000..a9cc6ce --- /dev/null +++ b/src/test/java/jota/AddressGenerationTest.java @@ -0,0 +1,20 @@ +package jota; + +import jota.utils.IotaAPIUtils; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Adrian on 02.12.2016. + */ +public class AddressGenerationTest { + private static String TEST_SEED = "ZEB99QTOMYDSKIFCXTLTVSWQFKO9CRKQKMRDR9HWVOVSGZMWPFQIMSCXXWUULHD9MZKMFJZAYZHZYA9VZ"; + private static String FIRST_ADDRESS = "LCZXWAQUHBXST9IEPPMJICTWLKJA9HVASXWDIRCVNM9TUAGZY9SRRJLZMZQIZKBAESXXNABFATUAYQYYW"; + + @Test + public void shouldAddChecksum() { + assertEquals(IotaAPIUtils.getNewAddress(TEST_SEED,0),FIRST_ADDRESS); + } + +} diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index 685aa62..2efaec0 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -1,6 +1,7 @@ package jota; import jota.utils.Checksum; +import jota.utils.InputValidator; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -10,8 +11,9 @@ import static org.junit.Assert.assertEquals; */ public class ChecksumTest { - private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTH"; - private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVA"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAFOXM9MUBX"; + @Test public void shouldAddChecksum() { assertEquals(Checksum.addChecksum(TEST_ADDRESS_WITHOUT_CHECKSUM), TEST_ADDRESS_WITH_CHECKSUM); @@ -21,9 +23,4 @@ public class ChecksumTest { public void shouldRemoveChecksum() { assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); } - - @Test - public void shouldIsValidChecksum() { - assertEquals(Checksum.isValidChecksum(TEST_ADDRESS_WITH_CHECKSUM), true); - } } From f697dac422c61da3e89a5c1a86e8eb8bc9a9373f Mon Sep 17 00:00:00 2001 From: Gianluigi Davassi Date: Fri, 2 Dec 2016 23:57:44 +0100 Subject: [PATCH 008/111] @pinpong fixed getNewAddress (#4) * implemented toTrytes and toStrings * added TrytesConverterTest * WIP * added checksum calculation, pls review * updated checksum * updated tests * fixed getnewaddress --- node_config.properties | 2 +- .../response/AnalyzeTransactionResponse.java | 83 ++-------------- .../jota/dto/response/GetBundleResponse.java | 90 ++--------------- .../dto/response/GetNeighborsResponse.java | 33 ++----- .../dto/response/GetTransfersResponse.java | 43 ++------ src/main/java/jota/model/Neighbor.java | 36 +++++++ src/main/java/jota/model/Transaction.java | 99 +++++++++++++++++++ src/main/java/jota/model/Transfer.java | 50 ++++++++++ src/main/java/jota/utils/Checksum.java | 42 ++++++++ src/main/java/jota/utils/Constants.java | 13 +++ src/main/java/jota/utils/Converter.java | 17 +++- src/main/java/jota/utils/Curl.java | 5 +- src/main/java/jota/utils/InputValidator.java | 22 +++++ src/main/java/jota/utils/IotaAPIUtils.java | 5 + src/main/java/jota/utils/Signing.java | 18 ++-- src/main/java/jota/utils/TrytesConverter.java | 90 +++++++++++++++++ src/test/java/jota/AddressGenerationTest.java | 20 ++++ src/test/java/jota/ChecksumTest.java | 26 +++++ src/test/java/jota/InputValidatorTest.java | 30 ++++++ src/test/java/jota/IotaAPIProxyTest.java | 8 +- src/test/java/jota/TrytesConverterTest.java | 21 ++++ 21 files changed, 511 insertions(+), 242 deletions(-) create mode 100644 src/main/java/jota/model/Neighbor.java create mode 100644 src/main/java/jota/model/Transaction.java create mode 100644 src/main/java/jota/model/Transfer.java create mode 100644 src/main/java/jota/utils/Checksum.java create mode 100644 src/main/java/jota/utils/Constants.java create mode 100644 src/main/java/jota/utils/InputValidator.java create mode 100644 src/main/java/jota/utils/TrytesConverter.java create mode 100644 src/test/java/jota/AddressGenerationTest.java create mode 100644 src/test/java/jota/ChecksumTest.java create mode 100644 src/test/java/jota/InputValidatorTest.java create mode 100644 src/test/java/jota/TrytesConverterTest.java diff --git a/node_config.properties b/node_config.properties index f3c3793..e5e5a5a 100644 --- a/node_config.properties +++ b/node_config.properties @@ -1,5 +1,5 @@ iota.node.protocol=http #iota.node.host=138.68.126.141 -iota.node.host=127.0.0.1 +iota.node.host=node.iotawallet.info iota.node.port=14265 diff --git a/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java b/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java index fdb7059..53081ff 100644 --- a/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java +++ b/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java @@ -1,86 +1,15 @@ package jota.dto.response; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import jota.model.Transaction; + +import java.util.ArrayList; +import java.util.List; public class AnalyzeTransactionResponse extends AbstractResponse { - private Transactions[] transactions; + private List transactions = new ArrayList(); - public Transactions[] getTransactions() { + public List getTransactions() { return transactions; } - - static class Transactions { - private String signatureMessageChunk; - private String index; - private String approvalNonce; - private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; - private String address; - private String value; - private String bundle; - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); - } - - public String getValue() { - return value; - } - - public String getDigest() { - return digest; - } - - public String getTrunkTransaction() { - return trunkTransaction; - } - - public String getTimestamp() { - return timestamp; - } - - public String getSignatureNonce() { - return signatureNonce; - } - - public String getType() { - return type; - } - - public String getAddress() { - return address; - } - - public String getApprovalNonce() { - return approvalNonce; - } - - public String getBranchTransaction() { - return branchTransaction; - } - - public String getBundle() { - return bundle; - } - - public String getHash() { - return hash; - } - - public String getIndex() { - return index; - } - - public String getSignatureMessageChunk() { - return signatureMessageChunk; - } - } } diff --git a/src/main/java/jota/dto/response/GetBundleResponse.java b/src/main/java/jota/dto/response/GetBundleResponse.java index c508f78..278631f 100644 --- a/src/main/java/jota/dto/response/GetBundleResponse.java +++ b/src/main/java/jota/dto/response/GetBundleResponse.java @@ -1,93 +1,15 @@ package jota.dto.response; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import jota.model.Transaction; + +import java.util.ArrayList; +import java.util.List; public class GetBundleResponse extends AbstractResponse { - public Transactions[] transactions; + private List transactions = new ArrayList<>(); - private String warning; - - public String getWarning() { - return warning; - } - - public Transactions[] getTransactions() { + public List getTransactions() { return transactions; } - - public static class Transactions { - private String signatureMessageChunk; - private String index; - private String approvalNonce; - private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; - private String address; - private String value; - private String bundle; - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); - } - - public String getAddress() { - return address; - } - - public String getApprovalNonce() { - return approvalNonce; - } - - public String getBranchTransaction() { - return branchTransaction; - } - - public String getBundle() { - return bundle; - } - - public String getDigest() { - return digest; - } - - public String getHash() { - return hash; - } - - public String getIndex() { - return index; - } - - public String getSignatureMessageChunk() { - return signatureMessageChunk; - } - - public String getSignatureNonce() { - return signatureNonce; - } - - public String getTimestamp() { - return timestamp; - } - - public String getType() { - return type; - } - - public String getTrunkTransaction() { - return trunkTransaction; - } - - public String getValue() { - return value; - } - - } } diff --git a/src/main/java/jota/dto/response/GetNeighborsResponse.java b/src/main/java/jota/dto/response/GetNeighborsResponse.java index 550a546..3740307 100644 --- a/src/main/java/jota/dto/response/GetNeighborsResponse.java +++ b/src/main/java/jota/dto/response/GetNeighborsResponse.java @@ -1,34 +1,15 @@ package jota.dto.response; +import jota.model.Neighbor; + +import java.util.ArrayList; +import java.util.List; + public class GetNeighborsResponse extends AbstractResponse { - public Neighbors[] neighbors; + private List neighbors = new ArrayList<>(); - public Neighbors[] getNeighbors() { + public List getNeighbors() { return neighbors; } - - public static class Neighbors { - - private String address; - private Integer numberOfAllTransactions; - private Integer numberOfInvalidTransactions; - private Integer numberOfNewTransactions; - - public String getAddress() { - return address; - } - - public Integer getNumberOfAllTransactions() { - return numberOfAllTransactions; - } - - public Integer getNumberOfInvalidTransactions() { - return numberOfInvalidTransactions; - } - - public Integer getNumberOfNewTransactions() { - return numberOfNewTransactions; - } - } } diff --git a/src/main/java/jota/dto/response/GetTransfersResponse.java b/src/main/java/jota/dto/response/GetTransfersResponse.java index 4046ad4..441ccea 100644 --- a/src/main/java/jota/dto/response/GetTransfersResponse.java +++ b/src/main/java/jota/dto/response/GetTransfersResponse.java @@ -1,46 +1,15 @@ package jota.dto.response; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import jota.model.Transfer; + +import java.util.ArrayList; +import java.util.List; public class GetTransfersResponse extends AbstractResponse { - private Transfers[] transfers; + private List transfers = new ArrayList<>(); - public Transfers[] getTransfers() { + public List getTransfers() { return transfers; } - - public static class Transfers { - private String timestamp; - private String address; - private String hash; - private Integer persistence; - private long value; - - public String getAddress() { - return address; - } - - public String getHash() { - return hash; - } - - public Integer getPersistence() { - return persistence; - } - - public String getTimestamp() { - return timestamp; - } - - public long getValue() { - return value; - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); - } - } } diff --git a/src/main/java/jota/model/Neighbor.java b/src/main/java/jota/model/Neighbor.java new file mode 100644 index 0000000..2eee719 --- /dev/null +++ b/src/main/java/jota/model/Neighbor.java @@ -0,0 +1,36 @@ +package jota.model; + +/** + * Created by pinpong on 02.12.16. + */ +public class Neighbor { + + private String address; + private Integer numberOfAllTransactions; + private Integer numberOfInvalidTransactions; + private Integer numberOfNewTransactions; + + public Neighbor(String address, Integer numberOfAllTransactions, Integer numberOfInvalidTransactions, Integer numberOfNewTransactions) { + this.address = address; + this.numberOfAllTransactions = numberOfAllTransactions; + this.numberOfInvalidTransactions = numberOfInvalidTransactions; + this.numberOfNewTransactions = numberOfNewTransactions; + } + + public String getAddress() { + return address; + } + + public Integer getNumberOfAllTransactions() { + return numberOfAllTransactions; + } + + public Integer getNumberOfInvalidTransactions() { + return numberOfInvalidTransactions; + } + + public Integer getNumberOfNewTransactions() { + return numberOfNewTransactions; + } + +} diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java new file mode 100644 index 0000000..4cf5e89 --- /dev/null +++ b/src/main/java/jota/model/Transaction.java @@ -0,0 +1,99 @@ +package jota.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by pinpong on 02.12.16. + */ +public class Transaction { + + private String signatureMessageChunk; + private String index; + private String approvalNonce; + private String hash; + private String digest; + private String type; + private String timestamp; + private String trunkTransaction; + private String branchTransaction; + private String signatureNonce; + private String address; + private String value; + private String bundle; + + public Transaction(String signatureMessageChunk, String index, String approvalNonce, String hash, String digest, String type, String timestamp, String trunkTransaction, String branchTransaction, String signatureNonce, String address, String value, String bundle) { + + this.hash = hash; + this.type = type; + this.signatureMessageChunk = signatureMessageChunk; + this.digest = digest; + this.address = address; + this.value = value; + this.timestamp = timestamp; + this.index = index; + this.bundle = bundle; + this.signatureNonce = signatureNonce; + this.approvalNonce = approvalNonce; + this.trunkTransaction = trunkTransaction; + this.branchTransaction = branchTransaction; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getValue() { + return value; + } + + public String getDigest() { + return digest; + } + + public String getTrunkTransaction() { + return trunkTransaction; + } + + public String getTimestamp() { + return timestamp; + } + + public String getSignatureNonce() { + return signatureNonce; + } + + public String getType() { + return type; + } + + public String getAddress() { + return address; + } + + public String getApprovalNonce() { + return approvalNonce; + } + + public String getBranchTransaction() { + return branchTransaction; + } + + public String getBundle() { + return bundle; + } + + public String getHash() { + return hash; + } + + public String getIndex() { + return index; + } + + public String getSignatureMessageChunk() { + return signatureMessageChunk; + } + +} diff --git a/src/main/java/jota/model/Transfer.java b/src/main/java/jota/model/Transfer.java new file mode 100644 index 0000000..fa149ee --- /dev/null +++ b/src/main/java/jota/model/Transfer.java @@ -0,0 +1,50 @@ +package jota.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by pinpong on 02.12.16. + */ +public class Transfer { + + private String timestamp; + private String address; + private String hash; + private Integer persistence; + private long value; + + public Transfer(String timestamp, String address, String hash, Integer persistence, long value) { + + this.timestamp = timestamp; + this.address = address; + this.hash = hash; + this.persistence = persistence; + this.value = value; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getAddress() { + return address; + } + + public String getHash() { + return hash; + } + + public Integer getPersistence() { + return persistence; + } + + public String getTimestamp() { + return timestamp; + } + + public long getValue() { + return value; + } +} diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java new file mode 100644 index 0000000..47e5567 --- /dev/null +++ b/src/main/java/jota/utils/Checksum.java @@ -0,0 +1,42 @@ +package jota.utils; + +/** + * Created by pinpong on 02.12.16. + */ +public class Checksum { + + public static String addChecksum(String address) { + InputValidator.checkAddress(address); + String addressWithChecksum = address; + addressWithChecksum += calculateChecksum(address); + return addressWithChecksum; + } + + public static String removeChecksum(String addressWithChecksum) { + if (isAddressWithChecksum(addressWithChecksum)) { + return getAddress(addressWithChecksum); + } else return ""; + } + + private static String getAddress(String addressWithChecksum) { + return addressWithChecksum.substring(0, Constants.addressLengthWithoutChecksum); + } + + public static boolean isValidChecksum(String addressWithChecksum) { + String addressWithoutChecksum = removeChecksum(addressWithChecksum); + String addressWithRecalculateChecksum = addressWithChecksum += calculateChecksum(addressWithoutChecksum); + return addressWithRecalculateChecksum.equals(addressWithChecksum); + } + + private static boolean isAddressWithChecksum(String addressWithChecksum) { + return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.addressLengthWithChecksum; + } + + public static String calculateChecksum(String address) { + Curl curl = new Curl(); + curl.reset(); + curl.setState(Converter.copyTrits(address, curl.getState())); + curl.transform(); + return Converter.trytes(curl.getState()).substring(0, 9); + } +} diff --git a/src/main/java/jota/utils/Constants.java b/src/main/java/jota/utils/Constants.java new file mode 100644 index 0000000..997b296 --- /dev/null +++ b/src/main/java/jota/utils/Constants.java @@ -0,0 +1,13 @@ +package jota.utils; + +/** + * Created by pinpong on 02.12.16. + */ +public class Constants { + + public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public static int addressLengthWithoutChecksum = 81; + public static int addressLengthWithChecksum = 90; + +} diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index be5313f..a43388f 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -9,7 +9,6 @@ public class Converter { public static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; public static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; - public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; @@ -63,7 +62,7 @@ public class Converter { final int[] trits = new int[trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE]; for (int i = 0; i < trytes.length(); i++) { - System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); + System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); } return trits; @@ -92,6 +91,16 @@ public class Converter { } } + public static int[] copyTrits(final String input, final int[] destination) { + for (int i = 0; i < input.length(); i++) { + int index = Constants.TRYTE_ALPHABET.indexOf(input.charAt(i)); + destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS [index][0]; + destination[i * 3 + 1] = TRYTE_TO_TRITS_MAPPINGS[index][1]; + destination[i * 3 + 2] = TRYTE_TO_TRITS_MAPPINGS[index][2]; + } + return destination; + } + public static String trytes(final int[] trits, final int offset, final int size) { StringBuilder trytes = new StringBuilder(); @@ -100,9 +109,9 @@ public class Converter { int j = trits[offset + i * 3] + trits[offset + i * 3 + 1] * 3 + trits[offset + i * 3 + 2] * 9; if (j < 0) { - j += TRYTE_ALPHABET.length(); + j += Constants.TRYTE_ALPHABET.length(); } - trytes.append(TRYTE_ALPHABET.charAt(j)); + trytes.append(Constants.TRYTE_ALPHABET.charAt(j)); } return trytes.toString(); } diff --git a/src/main/java/jota/utils/Curl.java b/src/main/java/jota/utils/Curl.java index b07236f..2c296e8 100644 --- a/src/main/java/jota/utils/Curl.java +++ b/src/main/java/jota/utils/Curl.java @@ -13,7 +13,7 @@ public class Curl { private static final int NUMBER_OF_ROUNDS = 27; private static final int[] TRUTH_TABLE = {1, 0, -1, 1, -1, 0, -1, 1, 0}; - private final int[] state = new int[STATE_LENGTH]; + private int[] state = new int[STATE_LENGTH]; public void absorb(final int[] trits, int offset, int length) { @@ -35,7 +35,7 @@ public class Curl { return state; } - private void transform() { + public void transform() { final int[] scratchpad = new int[STATE_LENGTH]; int scratchpadIndex = 0; @@ -56,4 +56,5 @@ public class Curl { public int[] getState() { return state; } + public void setState(int[] state) { this.state = state; } } diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java new file mode 100644 index 0000000..277a0ca --- /dev/null +++ b/src/main/java/jota/utils/InputValidator.java @@ -0,0 +1,22 @@ +package jota.utils; + +/** + * Created by pinpong on 02.12.16. + */ +public class InputValidator { + + public static boolean isAddress(String address) { + return (address.length() == Constants.addressLengthWithoutChecksum || + address.length() == Constants.addressLengthWithChecksum) && isTrytes(address, address.length()); + } + + public static boolean checkAddress(String address) { + if (!isAddress(address)) + throw new RuntimeException("Invalid address: " + address); + return true; + } + + public static boolean isTrytes(String trytes, int length) { + return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); + } +} diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index dd47181..5bcc294 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -18,8 +18,13 @@ public class IotaAPIUtils { public static GetNewAddressResponse getNewAddress(final String seed, final int index) { final int[] key = Signing.key(Converter.trits(seed), index, 2); + System.out.println("Length = "+ key.length ); final int[] digests = Signing.digests(key); + System.out.println("Length = "+ digests.length ); + final int[] addressTrits = Signing.address(digests); + System.out.println("Length = "+ addressTrits.length ); + final String address = Converter.trytes(addressTrits); return GetNewAddressResponse.create(address); diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 639a006..3cff61c 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -21,8 +21,10 @@ public class Signing { } Curl curl = new Curl(); - //curl.absorb(subseed, state); - //curl.squeeze(subseed, state); + curl.reset(); + curl.absorb(subseed, 0, subseed.length); + curl.squeeze(subseed, 0, subseed.length); + curl.reset(); curl.absorb(subseed, 0, subseed.length); List key = new ArrayList<>(); @@ -33,7 +35,7 @@ public class Signing { for (int i = 0; i < 27; i++) { - curl.squeeze(buffer, 0, buffer.length); + curl.squeeze(buffer, offset, buffer.length); for (int j = 0; j < 243; j++) { key.add(buffer[j]); } @@ -54,8 +56,8 @@ public class Signing { public static int[] digests(int[] key) { final Curl curl = new Curl(); - int[] digests = new int[key.length]; - int[] buffer = new int[key.length]; + int[] digests = new int[(int) Math.floor(key.length / 6561) * 243]; + int[] buffer = new int[243]; for (int i = 0; i < Math.floor(key.length / 6561); i++) { int[] keyFragment = Arrays.copyOfRange(key, i * 6561, (i + 1) * 6561); @@ -64,7 +66,7 @@ public class Signing { buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); for (int k = 0; k < 26; k++) { - + curl.reset(); curl.absorb(buffer, 0, buffer.length); curl.squeeze(buffer, 0, buffer.length); } @@ -74,6 +76,7 @@ public class Signing { } } + curl.reset(); curl.absorb(keyFragment, 0, keyFragment.length); curl.squeeze(buffer, 0, buffer.length); @@ -86,7 +89,8 @@ public class Signing { public static int[] address(int[] digests) { final Curl curl = new Curl(); - int[] address = new int[digests.length]; + int[] address = new int[243]; + curl.reset(); curl.absorb(digests, 0, digests.length); curl.squeeze(address, 0, address.length); return address; diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java new file mode 100644 index 0000000..4751b4a --- /dev/null +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -0,0 +1,90 @@ +package jota.utils; + +/** + * Created by pinpong on 01.12.16. + */ +public class TrytesConverter { + + /** + * Conversion of ascii encoded bytes to trytes. + * Input is a string (can be stringified JSON object), return value is Trytes + *

+ * How the conversion works: + * 2 Trytes === 1 Byte + * There are a total of 27 different tryte values: 9ABCDEFGHIJKLMNOPQRSTUVWXYZ + *

+ * 1. We get the decimal value of an individual ASCII character + * 2. From the decimal value, we then derive the two tryte values by basically calculating the tryte equivalent (e.g. 100 === 19 + 3 * 27) + * a. The first tryte value is the decimal value modulo 27 (27 trytes) + * b. The second value is the remainder (decimal value - first value), divided by 27 + * 3. The two values returned from Step 2. are then input as indices into the available values list ('9ABCDEFGHIJKLMNOPQRSTUVWXYZ') to get the correct tryte value + *

+ * EXAMPLES + * Lets say we want to convert the ASCII character "Z". + * 1. 'Z' has a decimal value of 90. + * 2. 90 can be represented as 9 + 3 * 27. To make it simpler: + * a. First value: 90 modulo 27 is 9. This is now our first value + * b. Second value: (90 - 9) / 27 is 3. This is our second value. + * 3. Our two values are now 9 and 3. To get the tryte value now we simply insert it as indices into '9ABCDEFGHIJKLMNOPQRSTUVWXYZ' + * a. The first tryte value is '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'[9] === "I" + * b. The second tryte value is '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'[3] === "C" + * Our tryte pair is "IC" + *

+ * RESULT: + * The ASCII char "Z" is represented as "IC" in trytes. + */ + + public static String toTrytes(String inputString) { + + String trytes = ""; + + for (int i = 0; i < inputString.length(); i++) { + + char asciiValue = inputString.charAt(i); + + // If not recognizable ASCII character, replace with space + if (asciiValue > 255) { + asciiValue = 32; + } + + int firstValue = asciiValue % 27; + int secondValue = (asciiValue - firstValue) / 27; + + String trytesValue = String.valueOf(Constants.TRYTE_ALPHABET.charAt(firstValue) + String.valueOf(Constants.TRYTE_ALPHABET.charAt(secondValue))); + + trytes += trytesValue; + } + + return trytes; + } + + /** + * Trytes to bytes + * Reverse operation from the byteToTrytes function in send.js + * 2 Trytes == 1 Byte + * We assume that the trytes are a JSON encoded object thus for our encoding: + * First character = { + * Last character = } + * Everything after that is 9's padding + */ + + public static String toString(String inputTrytes) { + + String string = ""; + + for (int i = 0; i < inputTrytes.length(); i += 2) { + // get a trytes pair + + int firstValue = Constants.TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i)); + int secondValue = Constants.TRYTE_ALPHABET.indexOf(inputTrytes.charAt(i + 1)); + + int decimalValue = firstValue + secondValue * 27; + + String character = Character.toString((char) decimalValue); + + string += character; + } + + return string; + } +} diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java new file mode 100644 index 0000000..a9cc6ce --- /dev/null +++ b/src/test/java/jota/AddressGenerationTest.java @@ -0,0 +1,20 @@ +package jota; + +import jota.utils.IotaAPIUtils; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by Adrian on 02.12.2016. + */ +public class AddressGenerationTest { + private static String TEST_SEED = "ZEB99QTOMYDSKIFCXTLTVSWQFKO9CRKQKMRDR9HWVOVSGZMWPFQIMSCXXWUULHD9MZKMFJZAYZHZYA9VZ"; + private static String FIRST_ADDRESS = "LCZXWAQUHBXST9IEPPMJICTWLKJA9HVASXWDIRCVNM9TUAGZY9SRRJLZMZQIZKBAESXXNABFATUAYQYYW"; + + @Test + public void shouldAddChecksum() { + assertEquals(IotaAPIUtils.getNewAddress(TEST_SEED,0),FIRST_ADDRESS); + } + +} diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java new file mode 100644 index 0000000..2efaec0 --- /dev/null +++ b/src/test/java/jota/ChecksumTest.java @@ -0,0 +1,26 @@ +package jota; + +import jota.utils.Checksum; +import jota.utils.InputValidator; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 02.12.16. + */ +public class ChecksumTest { + + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVA"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAFOXM9MUBX"; + + @Test + public void shouldAddChecksum() { + assertEquals(Checksum.addChecksum(TEST_ADDRESS_WITHOUT_CHECKSUM), TEST_ADDRESS_WITH_CHECKSUM); + } + + @Test + public void shouldRemoveChecksum() { + assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); + } +} diff --git a/src/test/java/jota/InputValidatorTest.java b/src/test/java/jota/InputValidatorTest.java new file mode 100644 index 0000000..5f4795e --- /dev/null +++ b/src/test/java/jota/InputValidatorTest.java @@ -0,0 +1,30 @@ +package jota; + +import jota.utils.InputValidator; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 02.12.16. + */ +public class InputValidatorTest { + + private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; + + @Test + public void shouldIsAddress() { + assertEquals(InputValidator.isAddress(TEST_ADDRESS_WITHOUT_CHECKSUM), true); + } + + @Test + public void shouldCheckAddress() { + assertEquals(InputValidator.checkAddress(TEST_ADDRESS_WITHOUT_CHECKSUM), true); + } + + @Test + public void shouldIsTrytes() { + assertEquals(InputValidator.isTrytes(TEST_TRYTES, TEST_TRYTES.length()), true); + } +} diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 5a9d1e4..cb5dda3 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -20,7 +20,8 @@ public class IotaAPIProxyTest { private static Gson gson = new GsonBuilder().create(); private static final String TEST_SEED = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; - private static final String TEST_ADDRESS = "RVORZ9SIIP9RCYMREUIXXVPQIPHVCNPQ9HZWYKFWYWZRE9JQKG9REPKIASHUUECPSQO9JT9XNMVKWYGVAZETAIRPTM"; + 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_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; private static final String TEST_MILESTONE = "SMYMAKKPSUKCKDRUEYCGZJTYCZ9HHDMDUWBAPXARGURPQRHTAJDASRWMIDTPTBNDKDEFBUTBGGAFX9999"; @@ -65,7 +66,7 @@ public class IotaAPIProxyTest { @Test public void shouldFindTransactionsByAddresses() { - FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS); + FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS_WITH_CHECKSUM); System.err.println(gson.toJson(trans)); assertThat(trans, IsNull.notNullValue()); } @@ -99,7 +100,7 @@ public class IotaAPIProxyTest { @Test public void shouldGetInclusionStates() { - GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS}, + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"123"}); assertThat(res, IsNull.notNullValue()); } @@ -128,5 +129,4 @@ public class IotaAPIProxyTest { GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 2); System.err.println(res); } - } \ No newline at end of file diff --git a/src/test/java/jota/TrytesConverterTest.java b/src/test/java/jota/TrytesConverterTest.java new file mode 100644 index 0000000..7741cff --- /dev/null +++ b/src/test/java/jota/TrytesConverterTest.java @@ -0,0 +1,21 @@ +package jota; + +import jota.utils.TrytesConverter; +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 01.12.16. + */ +public class TrytesConverterTest { + + @Test + public void shouldConvertStringToTrytes() { + assertEquals(TrytesConverter.toTrytes("Z"), "IC"); + } + @Test + public void shouldConvertTrytesToString() { + assertEquals(TrytesConverter.toString("IC"), "Z"); + } + +} From 2cb221c227324ea1be653fb5b447892545569e25 Mon Sep 17 00:00:00 2001 From: davassi Date: Sat, 3 Dec 2016 00:01:21 +0100 Subject: [PATCH 009/111] updated getNewAddress Test --- src/main/java/jota/utils/IotaAPIUtils.java | 9 +++++---- src/test/java/jota/IotaAPIProxyTest.java | 6 ++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 5bcc294..bc26d80 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -18,12 +18,13 @@ public class IotaAPIUtils { public static GetNewAddressResponse getNewAddress(final String seed, final int index) { final int[] key = Signing.key(Converter.trits(seed), index, 2); - System.out.println("Length = "+ key.length ); + log.debug("key Length = {}", key.length ); + final int[] digests = Signing.digests(key); - System.out.println("Length = "+ digests.length ); - + log.debug("digests Length = {}", digests.length ); + final int[] addressTrits = Signing.address(digests); - System.out.println("Length = "+ addressTrits.length ); + log.debug("addressTrits Length = {}", addressTrits.length ); final String address = Converter.trytes(addressTrits); diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index cb5dda3..bac2d3d 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -4,6 +4,8 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; import jota.utils.IotaAPIUtils; + +import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Before; import org.junit.Test; @@ -126,7 +128,7 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { - GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 2); - System.err.println(res); + GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 4); + assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); } } \ No newline at end of file From b579a6b48e202246ce0dd2b068246028568c950a Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 3 Dec 2016 00:08:41 +0100 Subject: [PATCH 010/111] fixed test --- src/main/java/jota/utils/IotaAPIUtils.java | 5 ----- src/test/java/jota/AddressGenerationTest.java | 20 ------------------- src/test/java/jota/ChecksumTest.java | 1 - src/test/java/jota/IotaAPIProxyTest.java | 4 ++-- 4 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 src/test/java/jota/AddressGenerationTest.java diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 5bcc294..dd47181 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -18,13 +18,8 @@ public class IotaAPIUtils { public static GetNewAddressResponse getNewAddress(final String seed, final int index) { final int[] key = Signing.key(Converter.trits(seed), index, 2); - System.out.println("Length = "+ key.length ); final int[] digests = Signing.digests(key); - System.out.println("Length = "+ digests.length ); - final int[] addressTrits = Signing.address(digests); - System.out.println("Length = "+ addressTrits.length ); - final String address = Converter.trytes(addressTrits); return GetNewAddressResponse.create(address); diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java deleted file mode 100644 index a9cc6ce..0000000 --- a/src/test/java/jota/AddressGenerationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package jota; - -import jota.utils.IotaAPIUtils; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Created by Adrian on 02.12.2016. - */ -public class AddressGenerationTest { - private static String TEST_SEED = "ZEB99QTOMYDSKIFCXTLTVSWQFKO9CRKQKMRDR9HWVOVSGZMWPFQIMSCXXWUULHD9MZKMFJZAYZHZYA9VZ"; - private static String FIRST_ADDRESS = "LCZXWAQUHBXST9IEPPMJICTWLKJA9HVASXWDIRCVNM9TUAGZY9SRRJLZMZQIZKBAESXXNABFATUAYQYYW"; - - @Test - public void shouldAddChecksum() { - assertEquals(IotaAPIUtils.getNewAddress(TEST_SEED,0),FIRST_ADDRESS); - } - -} diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index 2efaec0..69825c0 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -1,7 +1,6 @@ package jota; import jota.utils.Checksum; -import jota.utils.InputValidator; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index cb5dda3..b8cd2c7 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -8,6 +8,7 @@ import org.hamcrest.core.IsNull; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; /** @@ -126,7 +127,6 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { - GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 2); - System.err.println(res); + assertEquals(IotaAPIUtils.getNewAddress(TEST_SEED, 0).getAddress(), TEST_ADDRESS_WITH_CHECKSUM); } } \ No newline at end of file From 1146dd25cc3c7cbd706c7e3ac4bbedd5a1ad30f1 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 3 Dec 2016 00:21:32 +0100 Subject: [PATCH 011/111] updated node config --- node_config.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node_config.properties b/node_config.properties index e5e5a5a..f3c3793 100644 --- a/node_config.properties +++ b/node_config.properties @@ -1,5 +1,5 @@ iota.node.protocol=http #iota.node.host=138.68.126.141 -iota.node.host=node.iotawallet.info +iota.node.host=127.0.0.1 iota.node.port=14265 From cad499448b589658b772fdde7c90d155799b46a0 Mon Sep 17 00:00:00 2001 From: Gianluigi Davassi Date: Mon, 5 Dec 2016 23:49:35 +0100 Subject: [PATCH 012/111] Pinpong PR + refactoring (#7) * implemented toTrytes and toStrings * added TrytesConverterTest * WIP * added checksum calculation, pls review * updated checksum * updated tests * fixed getnewaddress * fixed test * updated node config * updated tests * newAddress * improved newAddress --- src/main/java/jota/IotaAPIProxy.java | 4 +- .../dto/response/GetNewAddressResponse.java | 16 ++-- src/main/java/jota/utils/IotaAPIUtils.java | 85 +++++++++++++++++-- src/main/java/jota/utils/IotaUnits.java | 4 + src/main/java/jota/utils/Signing.java | 27 +++--- src/test/java/jota/ChecksumTest.java | 6 +- src/test/java/jota/IotaAPIProxyTest.java | 5 +- 7 files changed, 114 insertions(+), 33 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index b742299..b1a07d3 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -195,8 +195,8 @@ public class IotaAPIProxy { return IotaAPIUtils.getBundle(transaction); } - public GetNewAddressResponse getNewAddress(String seed, Integer securityLevel) { - return IotaAPIUtils.getNewAddress(seed, securityLevel); + public GetNewAddressResponse getNewAddress(String seed, Integer index, boolean checksum, int total, boolean returnAll) { + return IotaAPIUtils.getNewAddress(seed, index, checksum, total, returnAll); } public static class Builder { diff --git a/src/main/java/jota/dto/response/GetNewAddressResponse.java b/src/main/java/jota/dto/response/GetNewAddressResponse.java index dab7d86..b54384d 100644 --- a/src/main/java/jota/dto/response/GetNewAddressResponse.java +++ b/src/main/java/jota/dto/response/GetNewAddressResponse.java @@ -1,16 +1,18 @@ package jota.dto.response; +import java.util.List; + public class GetNewAddressResponse extends AbstractResponse { - private String address; + private List addresses; - public String getAddress() { - return address; - } - - public static GetNewAddressResponse create(String address) { + public static GetNewAddressResponse create(List addresses) { GetNewAddressResponse res = new GetNewAddressResponse(); - res.address = address; + res.addresses = addresses; return res; } + + public List getAddress() { + return addresses; + } } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index bc26d80..8713502 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,11 +1,16 @@ package jota.utils; +import jota.IotaAPIProxy; +import jota.dto.response.FindTransactionResponse; import jota.dto.response.GetBundleResponse; import jota.dto.response.GetNewAddressResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; + /** * Client Side computation service * @@ -15,7 +20,75 @@ public class IotaAPIUtils { private static final Logger log = LoggerFactory.getLogger(IotaAPIUtils.class); - public static GetNewAddressResponse getNewAddress(final String seed, final int index) { + /** + * Generates a new address from a seed and returns the remainderAddress. + * This is either done deterministically, or by providing the index of the new remainderAddress + * + * @param seed Tryte-encoded seed. It should be noted that this seed is not transferred + * @param index Optional (default null). Key index to start search from. If the index is provided, the generation of the address is not deterministic. + * @param checksum Optional (default false). Adds 9-tryte address checksum + * @param total Optional (default 1)Total number of addresses to generate + * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) + * @return an array of strings with the specifed number of addresses + */ + + public static GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { + + final List allAddresses = new ArrayList<>(); + // Case 1: total + // + // If total number of addresses to generate is supplied, simply generate + // and return the list of all addresses + // + // + if (total != 0) { + // Increase index with each iteration + for (int i = index; i < index + total; i++) { + allAddresses.add(newAddress(seed, i, checksum)); + } + } + // Case 2: no total provided + // + // Continue calling findTransactions to see if address was already created + // if null, return list of addresses + // + else { + + // TODO init with params + IotaAPIProxy proxy = new IotaAPIProxy.Builder().build(); + + for (int i = index; ; i++) { + String newAddress = newAddress(seed, i, checksum); + + FindTransactionResponse response = proxy.findTransactions(null, new String[]{newAddress}, null, null); + + // If returnAll, return list of allAddresses + // else return only the last address that was generated + + if (!returnAll) { + allAddresses.clear(); + } + + allAddresses.add(newAddress); + + if (response.getHashes().length == 0) { + break; + } + } + } + + return GetNewAddressResponse.create(allAddresses); + } + + /** + * Generates a new address + * + * @param seed + * @param index + * @param checksum + * @return an String with address + */ + private static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); log.debug("key Length = {}", key.length ); @@ -24,14 +97,16 @@ public class IotaAPIUtils { log.debug("digests Length = {}", digests.length ); final int[] addressTrits = Signing.address(digests); - log.debug("addressTrits Length = {}", addressTrits.length ); + String address = Converter.trytes(addressTrits); - final String address = Converter.trytes(addressTrits); - - return GetNewAddressResponse.create(address); + if (checksum) { + address = Checksum.addChecksum(address); + } + return address; } public static GetBundleResponse getBundle(final String transaction) { throw new NotImplementedException("Not yet implemented"); } } + diff --git a/src/main/java/jota/utils/IotaUnits.java b/src/main/java/jota/utils/IotaUnits.java index f3fbfe0..28e52f3 100644 --- a/src/main/java/jota/utils/IotaUnits.java +++ b/src/main/java/jota/utils/IotaUnits.java @@ -3,6 +3,10 @@ package jota.utils; /** * Created by pinpong on 30.11.16. */ + +/** + * Table of IOTA units based off of the standard system of Units + **/ public enum IotaUnits { IOTA("i", 0), KILO_IOTA("Ki", 3), diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 3cff61c..025529e 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -8,27 +8,25 @@ public class Signing { static int[] key(int[] seed, int index, int length) { - final int[] subseed = seed; - for (int i = 0; i < index; i++) { for (int j = 0; j < 243; j++) { - if (++subseed[j] > 1) { - subseed[j] = -1; + if (++seed[j] > 1) { + seed[j] = -1; } else { break; } } } - Curl curl = new Curl(); + final Curl curl = new Curl(); curl.reset(); - curl.absorb(subseed, 0, subseed.length); - curl.squeeze(subseed, 0, subseed.length); + curl.absorb(seed, 0, seed.length); + curl.squeeze(seed, 0, seed.length); curl.reset(); - curl.absorb(subseed, 0, subseed.length); + curl.absorb(seed, 0, seed.length); - List key = new ArrayList<>(); - int[] buffer = new int[subseed.length]; + final List key = new ArrayList<>(); + int[] buffer = new int[seed.length]; int offset = 0; while (length-- > 0) { @@ -70,19 +68,14 @@ public class Signing { curl.absorb(buffer, 0, buffer.length); curl.squeeze(buffer, 0, buffer.length); } - for (int k = 0; k < 243; k++) { - - keyFragment[j * 243 + k] = buffer[k]; - } + System.arraycopy(buffer, 0, keyFragment, j * 243, 243); } curl.reset(); curl.absorb(keyFragment, 0, keyFragment.length); curl.squeeze(buffer, 0, buffer.length); - for (int j = 0; j < 243; j++) { - digests[i * 243 + j] = buffer[j]; - } + System.arraycopy(buffer, 0, digests, i * 243, 243); } return digests; } diff --git a/src/test/java/jota/ChecksumTest.java b/src/test/java/jota/ChecksumTest.java index 2efaec0..1413f69 100644 --- a/src/test/java/jota/ChecksumTest.java +++ b/src/test/java/jota/ChecksumTest.java @@ -1,7 +1,6 @@ package jota; import jota.utils.Checksum; -import jota.utils.InputValidator; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -23,4 +22,9 @@ public class ChecksumTest { public void shouldRemoveChecksum() { assertEquals(Checksum.removeChecksum(TEST_ADDRESS_WITH_CHECKSUM), TEST_ADDRESS_WITHOUT_CHECKSUM); } + + @Test + public void shouldIsValidChecksum() { + assertEquals(Checksum.isValidChecksum(TEST_ADDRESS_WITH_CHECKSUM), true); + } } diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index bac2d3d..b588479 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -10,6 +10,9 @@ import org.hamcrest.core.IsNull; import org.junit.Before; import org.junit.Test; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; /** @@ -128,7 +131,7 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { - GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 4); + final GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 4); assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); } } \ No newline at end of file From d0dbff07fe1b813e694643e2ca13147a3a7a6c43 Mon Sep 17 00:00:00 2001 From: davassi Date: Tue, 6 Dec 2016 00:21:39 +0100 Subject: [PATCH 013/111] refactoring, moving getNewAddress to Proxy class --- src/main/java/jota/IotaAPIProxy.java | 60 ++++++++++++++-- src/main/java/jota/utils/Checksum.java | 5 +- src/main/java/jota/utils/InputValidator.java | 3 +- src/main/java/jota/utils/IotaAPIUtils.java | 71 ++----------------- src/main/java/jota/utils/TrytesConverter.java | 6 +- src/test/java/jota/AddressGenerationTest.java | 2 +- src/test/java/jota/IotaAPIProxyTest.java | 6 +- 7 files changed, 73 insertions(+), 80 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index b1a07d3..617de2e 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -14,7 +14,9 @@ import retrofit2.converter.gson.GsonConverterFactory; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -184,19 +186,69 @@ public class IotaAPIProxy { return wrapCheckedException(res).body(); } - // end of proxied calls. - public BroadcastTransactionsResponse broadcastTransactions(String... trytes) { final Call res = service.broadcastTransactions(IotaBroadcastTransactionRequest.createBroadcastTransactionsRequest(trytes)); return wrapCheckedException(res).body(); } + // end of proxied calls. + public GetBundleResponse getBundle(String transaction) { return IotaAPIUtils.getBundle(transaction); } + + /** + * Generates a new address from a seed and returns the remainderAddress. + * This is either done deterministically, or by providing the index of the new remainderAddress + * + * @param seed Tryte-encoded seed. It should be noted that this seed is not transferred + * @param index Optional (default null). Key index to start search from. If the index is provided, the generation of the address is not deterministic. + * @param checksum Optional (default false). Adds 9-tryte address checksum + * @param total Optional (default 1)Total number of addresses to generate + * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) + * @return an array of strings with the specifed number of addresses + */ - public GetNewAddressResponse getNewAddress(String seed, Integer index, boolean checksum, int total, boolean returnAll) { - return IotaAPIUtils.getNewAddress(seed, index, checksum, total, returnAll); + public GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { + + final List allAddresses = new ArrayList<>(); + // Case 1: total + // + // If total number of addresses to generate is supplied, simply generate + // and return the list of all addresses + + if (total != 0) { + // Increase index with each iteration + for (int i = index; i < index + total; i++) { + allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); + } + return GetNewAddressResponse.create(allAddresses); + } + + // Case 2: no total provided + // + // Continue calling findTransactions to see if address was already created + // if null, return list of addresses + + for (int i = index; ; i++) { + String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); + + final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); + + allAddresses.add(newAddress); + + if (response.getHashes().length == 0) { + break; + } + } + + // If returnAll, return list of allAddresses + // else return only the last address that was generated + if (!returnAll) { + allAddresses.subList(0, allAddresses.size()-1).clear(); + } + + return GetNewAddressResponse.create(allAddresses); } public static class Builder { diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 47e5567..10a49de 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -1,5 +1,7 @@ package jota.utils; +import org.apache.commons.lang3.StringUtils; + /** * Created by pinpong on 02.12.16. */ @@ -15,7 +17,8 @@ public class Checksum { public static String removeChecksum(String addressWithChecksum) { if (isAddressWithChecksum(addressWithChecksum)) { return getAddress(addressWithChecksum); - } else return ""; + } + return StringUtils.EMPTY; } private static String getAddress(String addressWithChecksum) { diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 277a0ca..ed5f2ef 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -11,8 +11,9 @@ public class InputValidator { } public static boolean checkAddress(String address) { - if (!isAddress(address)) + if (!isAddress(address)) { throw new RuntimeException("Invalid address: " + address); + } return true; } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 8713502..d53fba5 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,15 +1,10 @@ package jota.utils; -import jota.IotaAPIProxy; -import jota.dto.response.FindTransactionResponse; -import jota.dto.response.GetBundleResponse; -import jota.dto.response.GetNewAddressResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.List; +import jota.dto.response.GetBundleResponse; /** * Client Side computation service @@ -20,66 +15,6 @@ public class IotaAPIUtils { private static final Logger log = LoggerFactory.getLogger(IotaAPIUtils.class); - /** - * Generates a new address from a seed and returns the remainderAddress. - * This is either done deterministically, or by providing the index of the new remainderAddress - * - * @param seed Tryte-encoded seed. It should be noted that this seed is not transferred - * @param index Optional (default null). Key index to start search from. If the index is provided, the generation of the address is not deterministic. - * @param checksum Optional (default false). Adds 9-tryte address checksum - * @param total Optional (default 1)Total number of addresses to generate - * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) - * @return an array of strings with the specifed number of addresses - */ - - public static GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { - - final List allAddresses = new ArrayList<>(); - // Case 1: total - // - // If total number of addresses to generate is supplied, simply generate - // and return the list of all addresses - // - // - if (total != 0) { - // Increase index with each iteration - for (int i = index; i < index + total; i++) { - allAddresses.add(newAddress(seed, i, checksum)); - } - } - // Case 2: no total provided - // - // Continue calling findTransactions to see if address was already created - // if null, return list of addresses - // - else { - - // TODO init with params - IotaAPIProxy proxy = new IotaAPIProxy.Builder().build(); - - for (int i = index; ; i++) { - String newAddress = newAddress(seed, i, checksum); - - FindTransactionResponse response = proxy.findTransactions(null, new String[]{newAddress}, null, null); - - // If returnAll, return list of allAddresses - // else return only the last address that was generated - - if (!returnAll) { - allAddresses.clear(); - } - - allAddresses.add(newAddress); - - if (response.getHashes().length == 0) { - break; - } - } - } - - return GetNewAddressResponse.create(allAddresses); - } - /** * Generates a new address * @@ -88,7 +23,7 @@ public class IotaAPIUtils { * @param checksum * @return an String with address */ - private static String newAddress(String seed, int index, boolean checksum) { + public static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); log.debug("key Length = {}", key.length ); @@ -97,6 +32,8 @@ public class IotaAPIUtils { log.debug("digests Length = {}", digests.length ); final int[] addressTrits = Signing.address(digests); + log.debug("addressTrits Length = {}", addressTrits.length ); + String address = Converter.trytes(addressTrits); if (checksum) { diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java index 4751b4a..21f560e 100644 --- a/src/main/java/jota/utils/TrytesConverter.java +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -36,7 +36,7 @@ public class TrytesConverter { public static String toTrytes(String inputString) { - String trytes = ""; + StringBuilder trytes = new StringBuilder(); for (int i = 0; i < inputString.length(); i++) { @@ -52,10 +52,10 @@ public class TrytesConverter { String trytesValue = String.valueOf(Constants.TRYTE_ALPHABET.charAt(firstValue) + String.valueOf(Constants.TRYTE_ALPHABET.charAt(secondValue))); - trytes += trytesValue; + trytes.append(trytesValue); } - return trytes; + return trytes.toString(); } /** diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java index a9cc6ce..3dfddea 100644 --- a/src/test/java/jota/AddressGenerationTest.java +++ b/src/test/java/jota/AddressGenerationTest.java @@ -14,7 +14,7 @@ public class AddressGenerationTest { @Test public void shouldAddChecksum() { - assertEquals(IotaAPIUtils.getNewAddress(TEST_SEED,0),FIRST_ADDRESS); + assertEquals(IotaAPIUtils.newAddress(TEST_SEED,0, false),FIRST_ADDRESS); } } diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index b588479..6a153ab 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -129,9 +129,9 @@ public class IotaAPIProxyTest { assertThat(proxy, IsNull.notNullValue()); } - @Test + /*@Test TODO Fix me public void shouldCreateANewAddress() { - final GetNewAddressResponse res = IotaAPIUtils.getNewAddress(TEST_SEED, 4); + final GetNewAddressResponse res = proxy.newAddress(TEST_SEED, 4, false); assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); - } + }*/ } \ No newline at end of file From 60d2664e04622c296ce2112b1da31810a7c1f0ee Mon Sep 17 00:00:00 2001 From: pinpong Date: Tue, 6 Dec 2016 21:45:41 +0100 Subject: [PATCH 014/111] updated tests --- src/main/java/jota/utils/IotaAPIUtils.java | 10 ++------ src/test/java/jota/AddressGenerationTest.java | 20 --------------- src/test/java/jota/IotaAPIProxyTest.java | 25 ++++++++----------- 3 files changed, 13 insertions(+), 42 deletions(-) delete mode 100644 src/test/java/jota/AddressGenerationTest.java diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index d53fba5..3da5c2d 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,11 +1,10 @@ package jota.utils; +import jota.dto.response.GetBundleResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jota.dto.response.GetBundleResponse; - /** * Client Side computation service * @@ -26,14 +25,9 @@ public class IotaAPIUtils { public static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); - log.debug("key Length = {}", key.length ); - final int[] digests = Signing.digests(key); - log.debug("digests Length = {}", digests.length ); - final int[] addressTrits = Signing.address(digests); - log.debug("addressTrits Length = {}", addressTrits.length ); - + String address = Converter.trytes(addressTrits); if (checksum) { diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java deleted file mode 100644 index 3dfddea..0000000 --- a/src/test/java/jota/AddressGenerationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package jota; - -import jota.utils.IotaAPIUtils; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Created by Adrian on 02.12.2016. - */ -public class AddressGenerationTest { - private static String TEST_SEED = "ZEB99QTOMYDSKIFCXTLTVSWQFKO9CRKQKMRDR9HWVOVSGZMWPFQIMSCXXWUULHD9MZKMFJZAYZHZYA9VZ"; - private static String FIRST_ADDRESS = "LCZXWAQUHBXST9IEPPMJICTWLKJA9HVASXWDIRCVNM9TUAGZY9SRRJLZMZQIZKBAESXXNABFATUAYQYYW"; - - @Test - public void shouldAddChecksum() { - assertEquals(IotaAPIUtils.newAddress(TEST_SEED,0, false),FIRST_ADDRESS); - } - -} diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 6a153ab..9b16cda 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,8 +3,6 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; -import jota.utils.IotaAPIUtils; - import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Before; @@ -12,7 +10,6 @@ import org.junit.Test; import java.util.Collections; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; /** @@ -78,19 +75,19 @@ public class IotaAPIProxyTest { @Test public void shouldFindTransactionsByApprovees() { - FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{TEST_HASH}); assertThat(trans, IsNull.notNullValue()); } @Test public void shouldFindTransactionsByBundles() { - FindTransactionResponse trans = proxy.findTransactionsByBundles(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByBundles(TEST_HASH); assertThat(trans, IsNull.notNullValue()); } @Test public void shouldFindTransactionsByDigests() { - FindTransactionResponse trans = proxy.findTransactionsByDigests(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByDigests(TEST_HASH); assertThat(trans, IsNull.notNullValue()); } @@ -100,13 +97,13 @@ public class IotaAPIProxyTest { @Test public void shouldGetTrytes() { GetTrytesResponse res = proxy.getTrytes(TEST_HASH); - assertThat(res, IsNull.nullValue()); + assertThat(res, IsNull.notNullValue()); + } @Test public void shouldGetInclusionStates() { - GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, - new String[]{"123"}); + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); assertThat(res, IsNull.notNullValue()); } @@ -118,7 +115,7 @@ public class IotaAPIProxyTest { @Test public void shouldGetBalances() { - GetBalancesResponse res = proxy.getBalances(100, new String[]{"HBBYKAKTILIPVUKFOTSLHGENPTXYBNKXZFQFR9VQFWNBMTQNRVOUKPVPRNBSZVVILMAFBKOTBLGLWLOHQ"}); + GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); System.err.println(res); assertThat(res, IsNull.notNullValue()); } @@ -129,9 +126,9 @@ public class IotaAPIProxyTest { assertThat(proxy, IsNull.notNullValue()); } - /*@Test TODO Fix me + @Test public void shouldCreateANewAddress() { - final GetNewAddressResponse res = proxy.newAddress(TEST_SEED, 4, false); - assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); - }*/ + final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); + assertThat(res.getAddress(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + } } \ No newline at end of file From 9173bb9fb6c71500b065e27b590987edc053347a Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Wed, 7 Dec 2016 15:19:24 +0100 Subject: [PATCH 015/111] updated tests (#8) --- src/main/java/jota/utils/IotaAPIUtils.java | 10 ++------ src/test/java/jota/AddressGenerationTest.java | 20 --------------- src/test/java/jota/IotaAPIProxyTest.java | 25 ++++++++----------- 3 files changed, 13 insertions(+), 42 deletions(-) delete mode 100644 src/test/java/jota/AddressGenerationTest.java diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index d53fba5..3da5c2d 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,11 +1,10 @@ package jota.utils; +import jota.dto.response.GetBundleResponse; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jota.dto.response.GetBundleResponse; - /** * Client Side computation service * @@ -26,14 +25,9 @@ public class IotaAPIUtils { public static String newAddress(String seed, int index, boolean checksum) { final int[] key = Signing.key(Converter.trits(seed), index, 2); - log.debug("key Length = {}", key.length ); - final int[] digests = Signing.digests(key); - log.debug("digests Length = {}", digests.length ); - final int[] addressTrits = Signing.address(digests); - log.debug("addressTrits Length = {}", addressTrits.length ); - + String address = Converter.trytes(addressTrits); if (checksum) { diff --git a/src/test/java/jota/AddressGenerationTest.java b/src/test/java/jota/AddressGenerationTest.java deleted file mode 100644 index 3dfddea..0000000 --- a/src/test/java/jota/AddressGenerationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package jota; - -import jota.utils.IotaAPIUtils; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Created by Adrian on 02.12.2016. - */ -public class AddressGenerationTest { - private static String TEST_SEED = "ZEB99QTOMYDSKIFCXTLTVSWQFKO9CRKQKMRDR9HWVOVSGZMWPFQIMSCXXWUULHD9MZKMFJZAYZHZYA9VZ"; - private static String FIRST_ADDRESS = "LCZXWAQUHBXST9IEPPMJICTWLKJA9HVASXWDIRCVNM9TUAGZY9SRRJLZMZQIZKBAESXXNABFATUAYQYYW"; - - @Test - public void shouldAddChecksum() { - assertEquals(IotaAPIUtils.newAddress(TEST_SEED,0, false),FIRST_ADDRESS); - } - -} diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 6a153ab..9b16cda 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,8 +3,6 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; -import jota.utils.IotaAPIUtils; - import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Before; @@ -12,7 +10,6 @@ import org.junit.Test; import java.util.Collections; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; /** @@ -78,19 +75,19 @@ public class IotaAPIProxyTest { @Test public void shouldFindTransactionsByApprovees() { - FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{TEST_HASH}); assertThat(trans, IsNull.notNullValue()); } @Test public void shouldFindTransactionsByBundles() { - FindTransactionResponse trans = proxy.findTransactionsByBundles(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByBundles(TEST_HASH); assertThat(trans, IsNull.notNullValue()); } @Test public void shouldFindTransactionsByDigests() { - FindTransactionResponse trans = proxy.findTransactionsByDigests(new String[]{"123ABC"}); + FindTransactionResponse trans = proxy.findTransactionsByDigests(TEST_HASH); assertThat(trans, IsNull.notNullValue()); } @@ -100,13 +97,13 @@ public class IotaAPIProxyTest { @Test public void shouldGetTrytes() { GetTrytesResponse res = proxy.getTrytes(TEST_HASH); - assertThat(res, IsNull.nullValue()); + assertThat(res, IsNull.notNullValue()); + } @Test public void shouldGetInclusionStates() { - GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, - new String[]{"123"}); + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); assertThat(res, IsNull.notNullValue()); } @@ -118,7 +115,7 @@ public class IotaAPIProxyTest { @Test public void shouldGetBalances() { - GetBalancesResponse res = proxy.getBalances(100, new String[]{"HBBYKAKTILIPVUKFOTSLHGENPTXYBNKXZFQFR9VQFWNBMTQNRVOUKPVPRNBSZVVILMAFBKOTBLGLWLOHQ"}); + GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); System.err.println(res); assertThat(res, IsNull.notNullValue()); } @@ -129,9 +126,9 @@ public class IotaAPIProxyTest { assertThat(proxy, IsNull.notNullValue()); } - /*@Test TODO Fix me + @Test public void shouldCreateANewAddress() { - final GetNewAddressResponse res = proxy.newAddress(TEST_SEED, 4, false); - assertThat(res.getAddress(), Is.is("GBPQGDMZ99FRNUBLCCIAXOEWNED9T9AMEHCGMMMFYTP9VINCVSNPAXUXBHQ9DIPTOOTP9XXUAUBDBMWMP")); - }*/ + final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); + assertThat(res.getAddress(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + } } \ No newline at end of file From 9dc1947234492fa81335c7b5c6a255392baf2cdb Mon Sep 17 00:00:00 2001 From: davassi Date: Wed, 7 Dec 2016 17:34:09 +0100 Subject: [PATCH 016/111] some refactoring --- src/main/java/jota/IotaAPIProxy.java | 25 +++++++------------- src/main/java/jota/{utils => pow}/Curl.java | 2 +- src/main/java/jota/utils/Checksum.java | 2 ++ src/main/java/jota/utils/InputValidator.java | 2 +- src/main/java/jota/utils/Signing.java | 2 ++ 5 files changed, 14 insertions(+), 19 deletions(-) rename src/main/java/jota/{utils => pow}/Curl.java (98%) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 617de2e..5ce6806 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -208,48 +208,39 @@ public class IotaAPIProxy { * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) * @return an array of strings with the specifed number of addresses */ - public GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { final List allAddresses = new ArrayList<>(); - // Case 1: total - // + // If total number of addresses to generate is supplied, simply generate // and return the list of all addresses - if (total != 0) { - // Increase index with each iteration for (int i = index; i < index + total; i++) { allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); } return GetNewAddressResponse.create(allAddresses); } - - // Case 2: no total provided - // - // Continue calling findTransactions to see if address was already created - // if null, return list of addresses - + // No total provided: Continue calling findTransactions to see if address was + // already created if null, return list of addresses for (int i = index; ; i++) { - String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); - + + final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); allAddresses.add(newAddress); - if (response.getHashes().length == 0) { break; } } - // If returnAll, return list of allAddresses - // else return only the last address that was generated + // If !returnAll return only the last address that was generated if (!returnAll) { allAddresses.subList(0, allAddresses.size()-1).clear(); } - return GetNewAddressResponse.create(allAddresses); } + + public static class Builder { diff --git a/src/main/java/jota/utils/Curl.java b/src/main/java/jota/pow/Curl.java similarity index 98% rename from src/main/java/jota/utils/Curl.java rename to src/main/java/jota/pow/Curl.java index 2c296e8..d72ed45 100644 --- a/src/main/java/jota/utils/Curl.java +++ b/src/main/java/jota/pow/Curl.java @@ -1,4 +1,4 @@ -package jota.utils; +package jota.pow; /** * (c) 2016 Come-from-Beyond diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 10a49de..fe22f5a 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -2,6 +2,8 @@ package jota.utils; import org.apache.commons.lang3.StringUtils; +import jota.pow.Curl; + /** * Created by pinpong on 02.12.16. */ diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index ed5f2ef..c1ddd2a 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -17,7 +17,7 @@ public class InputValidator { return true; } - public static boolean isTrytes(String trytes, int length) { + public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } } diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 025529e..a5e2553 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import jota.pow.Curl; + public class Signing { static int[] key(int[] seed, int index, int length) { From 8eedaefcdaeec30f8d1ddbecdee5eef7b630cec5 Mon Sep 17 00:00:00 2001 From: davassi Date: Wed, 7 Dec 2016 17:34:09 +0100 Subject: [PATCH 017/111] some refactoring --- src/main/java/jota/IotaAPIProxy.java | 25 +++++++------------- src/main/java/jota/{utils => pow}/Curl.java | 2 +- src/main/java/jota/utils/Checksum.java | 2 ++ src/main/java/jota/utils/InputValidator.java | 2 +- src/main/java/jota/utils/Signing.java | 2 ++ 5 files changed, 14 insertions(+), 19 deletions(-) rename src/main/java/jota/{utils => pow}/Curl.java (98%) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 617de2e..5ce6806 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -208,48 +208,39 @@ public class IotaAPIProxy { * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) * @return an array of strings with the specifed number of addresses */ - public GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { final List allAddresses = new ArrayList<>(); - // Case 1: total - // + // If total number of addresses to generate is supplied, simply generate // and return the list of all addresses - if (total != 0) { - // Increase index with each iteration for (int i = index; i < index + total; i++) { allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); } return GetNewAddressResponse.create(allAddresses); } - - // Case 2: no total provided - // - // Continue calling findTransactions to see if address was already created - // if null, return list of addresses - + // No total provided: Continue calling findTransactions to see if address was + // already created if null, return list of addresses for (int i = index; ; i++) { - String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); - + + final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); allAddresses.add(newAddress); - if (response.getHashes().length == 0) { break; } } - // If returnAll, return list of allAddresses - // else return only the last address that was generated + // If !returnAll return only the last address that was generated if (!returnAll) { allAddresses.subList(0, allAddresses.size()-1).clear(); } - return GetNewAddressResponse.create(allAddresses); } + + public static class Builder { diff --git a/src/main/java/jota/utils/Curl.java b/src/main/java/jota/pow/Curl.java similarity index 98% rename from src/main/java/jota/utils/Curl.java rename to src/main/java/jota/pow/Curl.java index 2c296e8..d72ed45 100644 --- a/src/main/java/jota/utils/Curl.java +++ b/src/main/java/jota/pow/Curl.java @@ -1,4 +1,4 @@ -package jota.utils; +package jota.pow; /** * (c) 2016 Come-from-Beyond diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 10a49de..fe22f5a 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -2,6 +2,8 @@ package jota.utils; import org.apache.commons.lang3.StringUtils; +import jota.pow.Curl; + /** * Created by pinpong on 02.12.16. */ diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index ed5f2ef..c1ddd2a 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -17,7 +17,7 @@ public class InputValidator { return true; } - public static boolean isTrytes(String trytes, int length) { + public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } } diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 025529e..a5e2553 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import jota.pow.Curl; + public class Signing { static int[] key(int[] seed, int index, int length) { From 84b60fbe6974cbb9e022f363ddbcdf5160d9fb74 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 18:29:22 +0100 Subject: [PATCH 018/111] [WIP ]tryfix getInputs, start to finish the god damn java lib --- src/main/java/jota/IotaAPIProxy.java | 466 ++++++++++++++---- .../dto/response/GetNewAddressResponse.java | 2 +- .../java/jota/error/ArgumentException.java | 14 + src/main/java/jota/error/BaseException.java | 51 ++ .../jota/error/NotEnoughBalanceException.java | 10 + src/main/java/jota/model/Input.java | 48 ++ src/main/java/jota/model/Inputs.java | 39 ++ src/main/java/jota/model/Transaction.java | 53 ++ src/main/java/jota/utils/IotaAPIUtils.java | 71 +++ 9 files changed, 660 insertions(+), 94 deletions(-) create mode 100644 src/main/java/jota/error/ArgumentException.java create mode 100644 src/main/java/jota/error/BaseException.java create mode 100644 src/main/java/jota/error/NotEnoughBalanceException.java create mode 100644 src/main/java/jota/model/Input.java create mode 100644 src/main/java/jota/model/Inputs.java diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 617de2e..6a77143 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -2,8 +2,12 @@ package jota; import jota.dto.request.*; import jota.dto.response.*; +import jota.error.ArgumentException; +import jota.error.NotEnoughBalanceException; +import jota.model.*; import jota.utils.IotaAPIUtils; import okhttp3.OkHttpClient; +import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import retrofit2.Call; @@ -14,21 +18,18 @@ import retrofit2.converter.gson.GsonConverterFactory; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Properties; +import java.util.*; 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 @@ -196,7 +197,7 @@ public class IotaAPIProxy { public GetBundleResponse getBundle(String transaction) { return IotaAPIUtils.getBundle(transaction); } - + /** * Generates a new address from a seed and returns the remainderAddress. * This is either done deterministically, or by providing the index of the new remainderAddress @@ -208,117 +209,396 @@ public class IotaAPIProxy { * @param returnAll If true, it returns all addresses which were deterministically generated (until findTransactions returns null) * @return an array of strings with the specifed number of addresses */ - public GetNewAddressResponse getNewAddress(final String seed, final int index, final boolean checksum, final int total, final boolean returnAll) { final List allAddresses = new ArrayList<>(); - // Case 1: total - // + // If total number of addresses to generate is supplied, simply generate // and return the list of all addresses - if (total != 0) { - // Increase index with each iteration for (int i = index; i < index + total; i++) { allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); } return GetNewAddressResponse.create(allAddresses); } - - // Case 2: no total provided - // - // Continue calling findTransactions to see if address was already created - // if null, return list of addresses - + // No total provided: Continue calling findTransactions to see if address was + // already created if null, return list of addresses for (int i = index; ; i++) { - String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); + final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); - + allAddresses.add(newAddress); - if (response.getHashes().length == 0) { break; } } - // If returnAll, return list of allAddresses - // else return only the last address that was generated + // If !returnAll return only the last address that was generated if (!returnAll) { - allAddresses.subList(0, allAddresses.size()-1).clear(); + allAddresses.subList(0, allAddresses.size() - 1).clear(); } - - return GetNewAddressResponse.create(allAddresses); + return GetNewAddressResponse.create(allAddresses); } - public static class Builder { + public Transaction[] sendTrytes(String[] trytes, int depth, int minWeightMagnitude) { + GetTransactionsToApproveResponse transactionsToApproveResponse = getTransactionsToApprove(depth); - String protocol, host, port; + GetAttachToTangleResponse attachToTangleResponse = + attachToTangle(transactionsToApproveResponse.getTrunkTransaction(), + transactionsToApproveResponse.getBranchTransactionToApprove(), minWeightMagnitude, trytes); - 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; - } + broadcastTransactions(attachToTangleResponse.getTrytes()); + return analyzeTransactions(attachToTangleResponse.getTrytes()); } -} + + private Transaction[] analyzeTransactions(String[] trytes) { + throw new NotImplementedException("MISSING"); + } + + /* + public Transaction[] SendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, int[] inputs, String address) { + // todo: check what to do with the optional arguments + String[] trytes = prepareTransfers(seed, transactions, inputs, address); + return sendTrytes(trytes, depth, minWeightMagnitude); + }*/ + + public Inputs GetInputs(String seed, Integer start, Integer end, int threshold) throws ArgumentException, NotEnoughBalanceException { + if (start < 0) + start = 0; + + if (end < 0) + end = 0; + + // If start value bigger than end, return error + if (start > end) + throw new ArgumentException(); + + // or if difference between end and start is bigger than 500 keys + if (end - start > 500) + throw new ArgumentException(); + + // Case 1: start and end + // + // If start and end is defined by the user, simply iterate through the keys + // and call getBalances + if (end != 0) { + String[] addresses = new String[end - start]; + + for (int i = start; i < end; i++) { + String address = IotaAPIUtils.newAddress(seed, i, false); + addresses[i] = address; + } + + return getBalancesaAndFormat(addresses, start, end, threshold); + } + + // Case 2: iterate till threshold || end + // + // Either start from index: 0 or start (if defined) until threshold is reached. + // Calls getNewAddress and deterministically generates and returns all addresses + // We then do getBalance, format the output and return it + else { + List addressList = getNewAddress(seed, start, true, 0,true).getAddresses(); + String[] addresses = addressList.toArray(new String[addressList.size()]); + return getBalancesaAndFormat(addresses, start, end, threshold); + } + } + + private Inputs getBalancesaAndFormat(String[] addresses) throws NotEnoughBalanceException{ + return getBalancesaAndFormat(addresses, null, null, null); + } + + private Inputs getBalancesaAndFormat(String[] addresses, Integer start, Integer end, Integer threshold) throws NotEnoughBalanceException { + GetBalancesResponse getBalancesResponse = getBalances(threshold, addresses); + + String[] balances = getBalancesResponse.getBalances(); + + Inputs inputs = new Inputs(new ArrayList(), 0); + + boolean threshholdReached = false; + + for (int i = 0; i < addresses.length; i++) { + if (Long.parseLong(balances[i]) > 0) { + inputs.getInputsList().add(new Input(addresses[i], Long.parseLong(balances[i]), start + i)); + inputs.setTotalBalance(inputs.getTotalBalance() + inputs.getInputsList().get(i).getBalance()); + + if (inputs.getTotalBalance() >= threshold) { + threshholdReached = true; + break; + } + } + } + + if (threshholdReached) + return inputs; + else { + throw new NotEnoughBalanceException(); + } + } + + //public String[] prepareTransfers(String seed, Transfer[] transfers, int[] inputs, String remainderAddress) { + //InputValidator.checkTransferArray(transfers); +/* + // If message or tag is not supplied, provide it + + for (Transfer transfer : transfers) { + + if (transfer.getAddress() == null) + transfer.getMessage().isEmpty(); + if (transfer.getTag() == null) + transfer.getMessage().isEmpty(); + } + + // Create a new bundle + Bundle bundle = new Bundle(); + long totalValue = 0; + List signatureFragments = new ArrayList(); + String tag = ""; + // + // Iterate over all transfers, get totalValue + // and prepare the signatureFragments, message and tag + // + for (Transfer transfer : transfers) { + int signatureMessageLength = 1; + + + // If message longer than 2187 trytes, increase signatureMessageLength (add 2nd transaction) + if (transfer.getMessage().length() > 2187) { + // Get total length, message / maxLength (2187 trytes) + signatureMessageLength += (int) Math.floor(((double) transfer.getMessage().length() / 2187)); + + String msgCopy = transfer.getMessage(); + + // While there is still a message, copy it + while (msgCopy != null) { + String fragment = msgCopy.substring(0, 2187); + msgCopy = msgCopy.substring(2187, msgCopy.length()); + + // Pad remainder of fragment + for (int j = 0; fragment.length() < 2187; j++) { + fragment += '9'; + } + + signatureFragments.add(fragment); + } + } else { + // Else, get single fragment with 2187 of 9's trytes + String fragment = ""; + + if (transfer.getMessage() != null) { + fragment = transfer.getMessage().substring(0, 2187); + } + + for (int j = 0; fragment.length() < 2187; j++) { + fragment += '9'; + } + + signatureFragments.add(fragment); + } + + // get current timestamp in seconds + // var timestamp = Math.floor(Date.now() / 1000); + long millis = System.currentTimeMillis() / 1000; + + // If no tag defined, get 27 tryte tag. + tag = transfer.getTag() != null ? transfer.getTag() : "999999999999999999999999999"; + + // Pad for required 27 tryte length + for (int j = 0; tag.length() < 27; j++) { + tag += '9'; + } + + // Add first entries to the bundle + // Slice the address in case the user provided a checksummed one + bundle.addEntry(signatureMessageLength, transfer.getAddress().substring(0, 81), transfer.getValue(), tag, millis); + // Sum up total value + totalValue += transfer.getValue(); + } + + // Get inputs if we are sending tokens + if (totalValue != 0) { + // Case 1: user provided inputs + // + // Validate the inputs by calling getBalances + if (inputs != null) { + // Get list if addresses of the provided inputs + + List inputAddresses = new ArrayList(); + for (int input : inputs) { + inputAddresses.add(input); + } + + GetBalancesResponse balances = getBalances(100, inputAddresses); + + List confirmedInputs = new ArrayList(); + + long totalBalance = 0; + for (int i = 0; i < balances.getBalances().length; i++) { + long thisBalance = Long.parseLong(balances.getBalances()[i]); + totalBalance += thisBalance; + + // If input has balance, add it to confirmedInputs + if (thisBalance > 0) { + long inputEl = inputs[i]; + inputEl = thisBalance; + + confirmedInputs.add(inputEl); + } + } + + // Return not enough balance error + if (totalValue > totalBalance) { + throw new NotEnoughBalanceException(totalBalance, totalValue); + } + + addRemainder(seed, confirmedInputs, totalValue, bundle, tag, remainderAddress, signatureFragments); + } + + // Case 2: Get inputs deterministically + // + // If no inputs provided, derive the addresses from the seed and + // confirm that the inputs exceed the threshold + else { + // todo getInputs should trow an exception if not enough balance + addRemainder(seed, GetInputs(seed, null, null, (int) totalValue).InputsList, + totalValue, bundle, tag, remainderAddress, signatureFragments); + } + } else { + // If no input required, don't sign and simply finalize the bundle + bundle.finalize(); + bundle.addTrytes(signatureFragments); + + List bundleTrytes = null; + // todo not sure what to add here + bundle.getLength().forEach(); + tx =>bundleTrytes.add(null); + + bundleTrytes.Reverse(); + return bundleTrytes.toArray(); + } + + // todo not sure what to return here too + return null; + } + + + private void addRemainder(String seed, List inputs, long totalValue, Bundle bundle, String tag, + String remainderAddress, List signatureFragments) { + for (Input input : inputs) { + long thisBalance = input.getBalance(); + long totalTransferValue = totalValue; + long toSubtract = 0 - thisBalance; + long timestamp = (new Date()).getTime(); + + // Add input as bundle entry + bundle.addEntry(2, input.getAddress(), toSubtract, tag, timestamp); + // If there is a remainder value + // Add extra output to send remaining funds to + + if (thisBalance >= totalTransferValue) { + long remainder = thisBalance - totalTransferValue; + + // If user has provided remainder address + // Use it to send remaining funds to + if (remainder > 0 && remainderAddress != null) { + // Remainder bundle entry + bundle.addEntry(1, remainderAddress, remainder, tag, timestamp); + + // Final function for signing inputs + IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } else if (remainder > 0) { + // Generate a new Address by calling getNewAddress + String address = getNewAddress(seed, 0, false, 0, false).getAddresses().get(0); + // Remainder bundle entry + bundle.addEntry(1, address, remainder, tag, timestamp); + + // Final function for signing inputs + IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } else { + // If there is no remainder, do not add transaction to bundle + // simply sign and return + IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } + + // If multiple inputs provided, subtract the totalTransferValue by + // the inputs balance + } else { + totalTransferValue -= thisBalance; + } + } + } + */ + + 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; + } + + } + } \ No newline at end of file diff --git a/src/main/java/jota/dto/response/GetNewAddressResponse.java b/src/main/java/jota/dto/response/GetNewAddressResponse.java index b54384d..484e17e 100644 --- a/src/main/java/jota/dto/response/GetNewAddressResponse.java +++ b/src/main/java/jota/dto/response/GetNewAddressResponse.java @@ -12,7 +12,7 @@ public class GetNewAddressResponse extends AbstractResponse { return res; } - public List getAddress() { + public List getAddresses() { return addresses; } } diff --git a/src/main/java/jota/error/ArgumentException.java b/src/main/java/jota/error/ArgumentException.java new file mode 100644 index 0000000..38eefb4 --- /dev/null +++ b/src/main/java/jota/error/ArgumentException.java @@ -0,0 +1,14 @@ +package jota.error; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * Created by Adrian on 09.12.2016. + */ +public class ArgumentException extends BaseException { + public ArgumentException() { + super("wrong arguments passed to function"); + } +} diff --git a/src/main/java/jota/error/BaseException.java b/src/main/java/jota/error/BaseException.java new file mode 100644 index 0000000..b1eb210 --- /dev/null +++ b/src/main/java/jota/error/BaseException.java @@ -0,0 +1,51 @@ +package jota.error; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * Created by Adrian on 09.12.2016. + */ +public class BaseException extends Exception { + protected Collection messages; + + public BaseException(String msg) { + super(msg); + } + + + public BaseException(String msg, Exception cause) { + super(msg, cause); + } + + + public BaseException(Collection messages) { + super(); + this.messages = messages; + } + + + public BaseException(Collection messages, Exception cause) { + super(cause); + this.messages = messages; + } + + @Override + public String getMessage() { + String msg; + + if (this.messages != null && !this.messages.isEmpty()) { + msg = "["; + + for (String message : this.messages) { + msg += message + ","; + } + + msg = StringUtils.removeEnd(msg, ",") + "]"; + + } else msg = super.getMessage(); + + return msg; + } +} diff --git a/src/main/java/jota/error/NotEnoughBalanceException.java b/src/main/java/jota/error/NotEnoughBalanceException.java new file mode 100644 index 0000000..c7099d6 --- /dev/null +++ b/src/main/java/jota/error/NotEnoughBalanceException.java @@ -0,0 +1,10 @@ +package jota.error; + +/** + * Created by Adrian on 09.12.2016. + */ +public class NotEnoughBalanceException extends BaseException { + public NotEnoughBalanceException() { + super("not enough balance dude"); + } +} diff --git a/src/main/java/jota/model/Input.java b/src/main/java/jota/model/Input.java new file mode 100644 index 0000000..8e3a53e --- /dev/null +++ b/src/main/java/jota/model/Input.java @@ -0,0 +1,48 @@ +package jota.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by Adrian on 09.12.2016. + */ +public class Input { + private String address; + private long balance; + private int keyIndex; + + public Input(String address, long balance, int keyIndex) { + this.address = address; + this.balance = balance; + this.keyIndex = keyIndex; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public long getBalance() { + return balance; + } + + public void setBalance(long balance) { + this.balance = balance; + } + + public int getKeyIndex() { + return keyIndex; + } + + public void setKeyIndex(int keyIndex) { + this.keyIndex = keyIndex; + } +} diff --git a/src/main/java/jota/model/Inputs.java b/src/main/java/jota/model/Inputs.java new file mode 100644 index 0000000..521d51d --- /dev/null +++ b/src/main/java/jota/model/Inputs.java @@ -0,0 +1,39 @@ +package jota.model; + +import com.google.gson.Gson; + +import java.util.List; + +/** + * Created by Adrian on 09.12.2016. + */ +public class Inputs { + private List inputsList; + private long totalBalance; + + public Inputs(List inputsList, long totalBalance) { + this.inputsList = inputsList; + this.totalBalance = totalBalance; + } + + @Override + public String toString() { + return new Gson().toJson(this); + } + + public List getInputsList() { + return inputsList; + } + + public void setInputsList(List inputsList) { + inputsList = inputsList; + } + + public long getTotalBalance() { + return totalBalance; + } + + public void setTotalBalance(long totalBalance) { + totalBalance = totalBalance; + } +} diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 4cf5e89..90e7231 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -44,6 +44,59 @@ public class Transaction { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); } + public void setSignatureMessageChunk(String signatureMessageChunk) { + + this.signatureMessageChunk = signatureMessageChunk; + } + + public void setIndex(String index) { + this.index = index; + } + + public void setApprovalNonce(String approvalNonce) { + this.approvalNonce = approvalNonce; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public void setDigest(String digest) { + this.digest = digest; + } + + public void setType(String type) { + this.type = type; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public void setTrunkTransaction(String trunkTransaction) { + this.trunkTransaction = trunkTransaction; + } + + public void setBranchTransaction(String branchTransaction) { + this.branchTransaction = branchTransaction; + } + + public void setSignatureNonce(String signatureNonce) { + this.signatureNonce = signatureNonce; + } + + public void setAddress(String address) { + this.address = address; + } + + public void setValue(String value) { + this.value = value; + } + + public void setBundle(String bundle) { + this.bundle = bundle; + } + public String getValue() { return value; } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 3da5c2d..7444800 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,10 +1,14 @@ package jota.utils; import jota.dto.response.GetBundleResponse; +import jota.model.Bundle; +import jota.model.Input; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + /** * Client Side computation service * @@ -39,5 +43,72 @@ public class IotaAPIUtils { public static GetBundleResponse getBundle(final String transaction) { throw new NotImplementedException("Not yet implemented"); } + + /* + public static List signInputsAndReturn(String seed, List inputs, Bundle bundle, + List signatureFragments) { + bundle.finalize(); + bundle.addTrytes(signatureFragments); + + // SIGNING OF INPUTS + // + // Here we do the actual signing of the inputs + // Iterate over all bundle transactions, find the inputs + // Get the corresponding private key and calculate the signatureFragment + for (int i = 0; i < bundle.getTransactions().size(); i++) { + if (Long.parseLong(bundle.getTransactions().get(i).getValue()) < 0) { + String thisAddress = bundle.getTransactions().get(i).getAddress(); + + // Get the corresponding keyIndex of the address + int keyIndex = 0; + for (int k = 0; k < inputs.size(); k++) { + if (inputs.get(k).getAddress().equals(thisAddress)) { + keyIndex = inputs.get(k).getKeyIndex(); + break; + } + } + + String bundleHash = bundle.getTransactions().get(i).getBundle(); + + // Get corresponding private key of address + int[] key = Signing.key(Converter.trits(seed), keyIndex, 2); + + // First 6561 trits for the firstFragment + var firstFragment = key.Take(6561); + + // Get the normalized bundle hash + String normalizedBundleHash = bundle.normalizedBundle(bundleHash); + /* + // First bundle fragment uses 27 trytes + var firstBundleFragment = normalizedBundleHash(27); + + // Calculate the new signatureFragment with the first bundle fragment + var firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); + + // Convert signature to trytes and assign the new signatureFragment + bundle.Transactions[i].signatureMessageFragment = Converter.trytes(firstSignedFragment); + + // Because the signature is > 2187 trytes, we need to + // find the second transaction to add the remainder of the signature + for (var j = 0; j < bundle.Transactions.Count; j++) + { + // Same address as well as value = 0 (as we already spent the input) + if (bundle.Transactions[j].Address == thisAddress && bundle.Transactions[j].Value == 0) + { + // Use the second 6562 trits + var secondFragment = key.Skip(6561).Take(6561); + + // The second 27 to 54 trytes of the bundle hash + var secondBundleFragment = normalizedBundleHash.slice(27, 27*2); + + // Calculate the new signature + var secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); + + // Convert signature to trytes and assign it again to this bundle entry + bundle.Transactions[j].signatureMessageFragment = Converter.trytes(secondSignedFragment); + } + }*/ + // } + // } } From ef915201da717ef22626b7b244aa7a0f3b4f37eb Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 18:43:19 +0100 Subject: [PATCH 019/111] bitch please --- src/main/java/jota/model/Bundle.java | 59 ++++++++++++++++++++++++++ src/main/java/jota/model/Transfer.java | 19 ++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/main/java/jota/model/Bundle.java diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java new file mode 100644 index 0000000..00aed02 --- /dev/null +++ b/src/main/java/jota/model/Bundle.java @@ -0,0 +1,59 @@ +package jota.model; + +import org.apache.commons.lang3.NotImplementedException; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Created by pinpong on 09.12.16. + */ +public class Bundle { + + private List transactions; + private int length; + + public Bundle() { + this(new ArrayList(), 0); + } + + public Bundle(List transactions, int length) { + this.transactions = transactions; + this.length = length; + } + + public List getTransactions() { + return transactions; + } + + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public void addEntry(int signatureMessageLength, String slice, long value, String tag, long timestamp) { + throw new NotImplementedException(""); + } + + public void finalize() { + throw new NotImplementedException(""); + } + + public void addTrytes(List signatureFragments) { + throw new NotImplementedException(""); + } + + public String normalizedBundle(String bundleHash) { + throw new NotImplementedException(""); + } + + +} diff --git a/src/main/java/jota/model/Transfer.java b/src/main/java/jota/model/Transfer.java index fa149ee..06080e2 100644 --- a/src/main/java/jota/model/Transfer.java +++ b/src/main/java/jota/model/Transfer.java @@ -1,5 +1,6 @@ package jota.model; +import com.google.gson.Gson; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -13,19 +14,24 @@ public class Transfer { private String hash; private Integer persistence; private long value; + private String message; + private String tag; - public Transfer(String timestamp, String address, String hash, Integer persistence, long value) { + public Transfer(String timestamp, String address, String hash, Integer persistence, long value, String message, String tag) { this.timestamp = timestamp; this.address = address; this.hash = hash; this.persistence = persistence; this.value = value; + this.message = message; + this.tag = tag; + } @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + return new Gson().toJson(this); } public String getAddress() { @@ -47,4 +53,13 @@ public class Transfer { public long getValue() { return value; } + + public String getMessage() { + return message; + } + + public String getTag() { + return tag; + } + } From 605703b38728b23f29860c3e746961ec822620f1 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 19:36:05 +0100 Subject: [PATCH 020/111] [WIP ] fixed getinput --- src/main/java/jota/IotaAPIProxy.java | 169 +++++++++++---------- src/main/java/jota/model/Inputs.java | 2 +- src/main/java/jota/utils/IotaAPIUtils.java | 106 +++++++++---- 3 files changed, 161 insertions(+), 116 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 6a77143..8319077 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -257,18 +257,18 @@ public class IotaAPIProxy { throw new NotImplementedException("MISSING"); } - /* +/* public Transaction[] SendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, int[] inputs, String address) { // todo: check what to do with the optional arguments String[] trytes = prepareTransfers(seed, transactions, inputs, address); return sendTrytes(trytes, depth, minWeightMagnitude); - }*/ - - public Inputs GetInputs(String seed, Integer start, Integer end, int threshold) throws ArgumentException, NotEnoughBalanceException { - if (start < 0) + } +*/ + public Inputs getInputs(String seed, Integer start, Integer end, int threshold) throws ArgumentException, NotEnoughBalanceException { + if (start == null || start < 0) start = 0; - if (end < 0) + if (end == null || end < 0) end = 0; // If start value bigger than end, return error @@ -291,7 +291,7 @@ public class IotaAPIProxy { addresses[i] = address; } - return getBalancesaAndFormat(addresses, start, end, threshold); + return getBalancesAndFormat(addresses, start, end, threshold); } // Case 2: iterate till threshold || end @@ -300,17 +300,17 @@ public class IotaAPIProxy { // Calls getNewAddress and deterministically generates and returns all addresses // We then do getBalance, format the output and return it else { - List addressList = getNewAddress(seed, start, true, 0,true).getAddresses(); + List addressList = getNewAddress(seed, start, true, 0, true).getAddresses(); String[] addresses = addressList.toArray(new String[addressList.size()]); - return getBalancesaAndFormat(addresses, start, end, threshold); + return getBalancesAndFormat(addresses, start, end, threshold); } } - private Inputs getBalancesaAndFormat(String[] addresses) throws NotEnoughBalanceException{ - return getBalancesaAndFormat(addresses, null, null, null); + private Inputs getBalancesAndFormat(String[] addresses) throws NotEnoughBalanceException { + return getBalancesAndFormat(addresses, null, null, null); } - private Inputs getBalancesaAndFormat(String[] addresses, Integer start, Integer end, Integer threshold) throws NotEnoughBalanceException { + private Inputs getBalancesAndFormat(String[] addresses, Integer start, Integer end, Integer threshold) throws NotEnoughBalanceException { GetBalancesResponse getBalancesResponse = getBalances(threshold, addresses); String[] balances = getBalancesResponse.getBalances(); @@ -337,10 +337,10 @@ public class IotaAPIProxy { throw new NotEnoughBalanceException(); } } - - //public String[] prepareTransfers(String seed, Transfer[] transfers, int[] inputs, String remainderAddress) { - //InputValidator.checkTransferArray(transfers); /* + public String[] prepareTransfers(String seed, Transfer[] transfers, String[] inputs, String remainderAddress) throws NotEnoughBalanceException,ArgumentException{ + //InputValidator.checkTransferArray(transfers); + // If message or tag is not supplied, provide it for (Transfer transfer : transfers) { @@ -425,12 +425,12 @@ public class IotaAPIProxy { if (inputs != null) { // Get list if addresses of the provided inputs - List inputAddresses = new ArrayList(); - for (int input : inputs) { + List inputAddresses = new ArrayList(); + for (String input : inputs) { inputAddresses.add(input); } - GetBalancesResponse balances = getBalances(100, inputAddresses); + GetBalancesResponse balances = getBalances(100, inputAddresses.toArray(new String[inputAddresses.size()])); List confirmedInputs = new ArrayList(); @@ -441,16 +441,17 @@ public class IotaAPIProxy { // If input has balance, add it to confirmedInputs if (thisBalance > 0) { - long inputEl = inputs[i]; - inputEl = thisBalance; + String inputEl = inputs[i]; + inputEl = thisBalance + ""; - confirmedInputs.add(inputEl); + confirmedInputs.add(new Input()); } } // Return not enough balance error if (totalValue > totalBalance) { - throw new NotEnoughBalanceException(totalBalance, totalValue); + //throw new NotEnoughBalanceException(totalBalance, totalValue); + throw new NotEnoughBalanceException(); } addRemainder(seed, confirmedInputs, totalValue, bundle, tag, remainderAddress, signatureFragments); @@ -531,74 +532,74 @@ public class IotaAPIProxy { } */ - public static class Builder { + public static class Builder { - String protocol, host, port; + String protocol, host, port; - public IotaAPIProxy build() { + public IotaAPIProxy build() { - if (protocol == null || host == null || port == null) { + if (protocol == null || host == null || port == null) { - // check properties files. - if (!checkPropertiesFiles()) { + // check properties files. + if (!checkPropertiesFiles()) { - // last resort: best effort on enviroment variable, - // before assigning default values. - checkEnviromentVariables(); - } + // 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; } + return new IotaAPIProxy(this); } - } \ No newline at end of file + + 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; + } + + } +} \ No newline at end of file diff --git a/src/main/java/jota/model/Inputs.java b/src/main/java/jota/model/Inputs.java index 521d51d..5d4b993 100644 --- a/src/main/java/jota/model/Inputs.java +++ b/src/main/java/jota/model/Inputs.java @@ -34,6 +34,6 @@ public class Inputs { } public void setTotalBalance(long totalBalance) { - totalBalance = totalBalance; + this.totalBalance = totalBalance; } } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 7444800..593b170 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -3,10 +3,14 @@ package jota.utils; import jota.dto.response.GetBundleResponse; import jota.model.Bundle; import jota.model.Input; +import jota.model.Transaction; import org.apache.commons.lang3.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -43,10 +47,43 @@ public class IotaAPIUtils { public static GetBundleResponse getBundle(final String transaction) { throw new NotImplementedException("Not yet implemented"); } +/* + public static String transactionTrytes(Transaction trx) { + int[] valueTrits = Converter.trits(trx.getValue()); + while (valueTrits.length < 81) { + valueTrits[valueTrits.length] = 0; + } - /* - public static List signInputsAndReturn(String seed, List inputs, Bundle bundle, - List signatureFragments) { + int[] timestampTrits = Converter.trits(trx.getTimestamp()); + while (timestampTrits.length < 27) { + timestampTrits[timestampTrits.length] = 0; + } + + int[] currentIndexTrits = Converter.trits(trx.getC); + while (currentIndexTrits.length < 27) { + currentIndexTrits[currentIndexTrits.length] = 0; + } + + int[] lastIndexTrits = Converter.trits(trx.get); + while (lastIndexTrits.length < 27) { + lastIndexTrits[lastIndexTrits.length] = 0; + } + + return trx.getSignatureMessageChunk() + + trx.getAddress() + + Converter.trytes(valueTrits) + + trx.getT + + Converter.trytes(timestampTrits) + + Converter.trytes(currentIndexTrits) + + Converter.trytes(lastIndexTrits) + + trx.bundle + + trx.trunkTransaction + + trx.branchTransaction + + trx.nonce; + } + + public static List signInputsAndReturn(String seed, List inputs, Bundle bundle, + List signatureFragments) { bundle.finalize(); bundle.addTrytes(signatureFragments); @@ -74,41 +111,48 @@ public class IotaAPIUtils { int[] key = Signing.key(Converter.trits(seed), keyIndex, 2); // First 6561 trits for the firstFragment - var firstFragment = key.Take(6561); + int[] firstFragment = Arrays.copyOfRange((6561); // Get the normalized bundle hash String normalizedBundleHash = bundle.normalizedBundle(bundleHash); - /* - // First bundle fragment uses 27 trytes - var firstBundleFragment = normalizedBundleHash(27); - // Calculate the new signatureFragment with the first bundle fragment - var firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); + // First bundle fragment uses 27 trytes + var firstBundleFragment = normalizedBundleHash(27); - // Convert signature to trytes and assign the new signatureFragment - bundle.Transactions[i].signatureMessageFragment = Converter.trytes(firstSignedFragment); + // Calculate the new signatureFragment with the first bundle fragment + var firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); - // Because the signature is > 2187 trytes, we need to - // find the second transaction to add the remainder of the signature - for (var j = 0; j < bundle.Transactions.Count; j++) - { - // Same address as well as value = 0 (as we already spent the input) - if (bundle.Transactions[j].Address == thisAddress && bundle.Transactions[j].Value == 0) - { - // Use the second 6562 trits - var secondFragment = key.Skip(6561).Take(6561); + // Convert signature to trytes and assign the new signatureFragment + bundle.Transactions[i].signatureMessageFragment = Converter.trytes(firstSignedFragment); - // The second 27 to 54 trytes of the bundle hash - var secondBundleFragment = normalizedBundleHash.slice(27, 27*2); + // Because the signature is > 2187 trytes, we need to + // find the second transaction to add the remainder of the signature + for (var j = 0; j < bundle.Transactions.Count; j++) { + // Same address as well as value = 0 (as we already spent the input) + if (bundle.Transactions[j].Address == thisAddress && bundle.Transactions[j].Value == 0) { + // Use the second 6562 trits + var secondFragment = key.Skip(6561).Take(6561); - // Calculate the new signature - var secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); + // The second 27 to 54 trytes of the bundle hash + var secondBundleFragment = normalizedBundleHash.slice(27, 27 * 2); - // Convert signature to trytes and assign it again to this bundle entry - bundle.Transactions[j].signatureMessageFragment = Converter.trytes(secondSignedFragment); - } - }*/ - // } - // } + // Calculate the new signature + var secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); + + // Convert signature to trytes and assign it again to this bundle entry + bundle.getTransactions().get(j).setSignatureMessageChunk(Converter.trytes(secondSignedFragment)); + } + } + } + } + + List bundleTrytes = new ArrayList<>(); + + // Convert all bundle entries into trytes + for (Transaction tx : bundle.getTransactions()) { + bundleTrytes.add(IotaAPIUtils.transactionTrytes(tx)); + } + Collections.reverse(bundleTrytes); + return bundleTrytes; + }*/ } - From e0a56e6359b3934b1b6b9815ce659adf7254c56f Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 9 Dec 2016 19:42:11 +0100 Subject: [PATCH 021/111] updated tests --- src/test/java/jota/IotaAPIProxyTest.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 9b16cda..ff912f9 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,6 +3,9 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; +import jota.error.ArgumentException; +import jota.error.NotEnoughBalanceException; +import jota.model.Inputs; import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Before; @@ -11,6 +14,7 @@ import org.junit.Test; import java.util.Collections; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** * Let's do some integration test coverage against a default local real node. @@ -129,6 +133,12 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); - assertThat(res.getAddress(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + assertThat(res.getAddresses(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + } + + @Test + public void shouldGetGetInputs() throws ArgumentException, NotEnoughBalanceException { + final Inputs res = proxy.getInputs(TEST_SEED, 0, 1, 1); + assertTrue(res.getTotalBalance() > 0); } } \ No newline at end of file From 94c6b4e2f21f512e1cda0f04ba45750146bbee89 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 20:21:37 +0100 Subject: [PATCH 022/111] updated trx object and normalizedBundle added --- src/main/java/jota/model/Bundle.java | 42 ++++++++- src/main/java/jota/model/Transaction.java | 100 ++++++++++------------ src/main/java/jota/utils/Converter.java | 8 ++ 3 files changed, 91 insertions(+), 59 deletions(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 00aed02..f6c7d7a 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -1,5 +1,6 @@ package jota.model; +import jota.utils.Converter; import org.apache.commons.lang3.NotImplementedException; import java.util.ArrayList; @@ -51,9 +52,44 @@ public class Bundle { throw new NotImplementedException(""); } - public String normalizedBundle(String bundleHash) { - throw new NotImplementedException(""); + public int[] normalizedBundle(String bundleHash) { + int[] normalizedBundle = new int[33 * 27 + 27]; + + for (int i = 0; i < 3; i++) { + + long sum = 0; + for (int j = 0; j < 27; j++) { + + sum += (normalizedBundle[i * 27 + j] = Converter.value(Converter.trits("" + bundleHash.charAt(i * 27 + j)))); + } + + if (sum >= 0) { + while (sum-- > 0) { + for (int j = 0; j < 27; j++) { + if (normalizedBundle[i * 27 + j] > -13) { + normalizedBundle[i * 27 + j]--; + break; + } + } + } + } else { + + while (sum++ < 0) { + + for (int j = 0; j < 27; j++) { + + if (normalizedBundle[i * 27 + j] < 13) { + + normalizedBundle[i * 27 + j]++; + break; + } + } + } + } + } + + return normalizedBundle; } - } + diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 90e7231..f8f45fa 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -7,36 +7,33 @@ import org.apache.commons.lang3.builder.ToStringStyle; * Created by pinpong on 02.12.16. */ public class Transaction { - - private String signatureMessageChunk; - private String index; - private String approvalNonce; private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; + private String signatureMessageChunk; private String address; private String value; + private String tag; + private String timestamp; + private String currentIndex; + private String lastIndex; private String bundle; + private String trunkTransaction; + private String branchTransaction; + private String nonce; - public Transaction(String signatureMessageChunk, String index, String approvalNonce, String hash, String digest, String type, String timestamp, String trunkTransaction, String branchTransaction, String signatureNonce, String address, String value, String bundle) { + public Transaction(String signatureMessageChunk, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { this.hash = hash; - this.type = type; + this.tag = tag; this.signatureMessageChunk = signatureMessageChunk; - this.digest = digest; this.address = address; this.value = value; this.timestamp = timestamp; - this.index = index; + this.currentIndex = currentIndex; + this.lastIndex = lastIndex; this.bundle = bundle; - this.signatureNonce = signatureNonce; - this.approvalNonce = approvalNonce; this.trunkTransaction = trunkTransaction; this.branchTransaction = branchTransaction; + this.nonce = nonce; } @Override @@ -49,26 +46,10 @@ public class Transaction { this.signatureMessageChunk = signatureMessageChunk; } - public void setIndex(String index) { - this.index = index; - } - - public void setApprovalNonce(String approvalNonce) { - this.approvalNonce = approvalNonce; - } - public void setHash(String hash) { this.hash = hash; } - public void setDigest(String digest) { - this.digest = digest; - } - - public void setType(String type) { - this.type = type; - } - public void setTimestamp(String timestamp) { this.timestamp = timestamp; } @@ -81,10 +62,6 @@ public class Transaction { this.branchTransaction = branchTransaction; } - public void setSignatureNonce(String signatureNonce) { - this.signatureNonce = signatureNonce; - } - public void setAddress(String address) { this.address = address; } @@ -101,10 +78,6 @@ public class Transaction { return value; } - public String getDigest() { - return digest; - } - public String getTrunkTransaction() { return trunkTransaction; } @@ -113,22 +86,10 @@ public class Transaction { return timestamp; } - public String getSignatureNonce() { - return signatureNonce; - } - - public String getType() { - return type; - } - public String getAddress() { return address; } - public String getApprovalNonce() { - return approvalNonce; - } - public String getBranchTransaction() { return branchTransaction; } @@ -141,12 +102,39 @@ public class Transaction { return hash; } - public String getIndex() { - return index; - } - public String getSignatureMessageChunk() { return signatureMessageChunk; } + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getCurrentIndex() { + return currentIndex; + } + + public void setCurrentIndex(String currentIndex) { + this.currentIndex = currentIndex; + } + + public String getLastIndex() { + return lastIndex; + } + + public void setLastIndex(String lastIndex) { + this.lastIndex = lastIndex; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } } diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index a43388f..c10792b 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -124,6 +124,14 @@ public class Converter { return trits[offset] + trits[offset + 1] * 3 + trits[offset + 2] * 9; } + public static int value(final int[] trits) { + int value = 0; + + for (int i = trits.length; i-- > 0; ) { + value = value * 3 + trits[i]; + } + return value; } + public static void increment(final int[] trits, final int size) { for (int i = 0; i < size; i++) { From 3c527ca7379722d2fbbdeb97062610f890c296cc Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 20:30:38 +0100 Subject: [PATCH 023/111] [WIP] added missing function to signing & iotaapiutils --- src/main/java/jota/utils/IotaAPIUtils.java | 38 ++++----- src/main/java/jota/utils/Signing.java | 99 ++++++++++++++++++++++ 2 files changed, 118 insertions(+), 19 deletions(-) diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 593b170..6f24a9d 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -47,7 +47,7 @@ public class IotaAPIUtils { public static GetBundleResponse getBundle(final String transaction) { throw new NotImplementedException("Not yet implemented"); } -/* + public static String transactionTrytes(Transaction trx) { int[] valueTrits = Converter.trits(trx.getValue()); while (valueTrits.length < 81) { @@ -59,12 +59,12 @@ public class IotaAPIUtils { timestampTrits[timestampTrits.length] = 0; } - int[] currentIndexTrits = Converter.trits(trx.getC); + int[] currentIndexTrits = Converter.trits(trx.getTimestamp()); while (currentIndexTrits.length < 27) { currentIndexTrits[currentIndexTrits.length] = 0; } - int[] lastIndexTrits = Converter.trits(trx.get); + int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex()); while (lastIndexTrits.length < 27) { lastIndexTrits[lastIndexTrits.length] = 0; } @@ -72,14 +72,14 @@ public class IotaAPIUtils { return trx.getSignatureMessageChunk() + trx.getAddress() + Converter.trytes(valueTrits) - + trx.getT + + trx.getTag() + Converter.trytes(timestampTrits) + Converter.trytes(currentIndexTrits) + Converter.trytes(lastIndexTrits) - + trx.bundle - + trx.trunkTransaction - + trx.branchTransaction - + trx.nonce; + + trx.getBundle() + + trx.getTrunkTransaction() + + trx.getBranchTransaction() + + trx.getNonce(); } public static List signInputsAndReturn(String seed, List inputs, Bundle bundle, @@ -111,33 +111,33 @@ public class IotaAPIUtils { int[] key = Signing.key(Converter.trits(seed), keyIndex, 2); // First 6561 trits for the firstFragment - int[] firstFragment = Arrays.copyOfRange((6561); + int[] firstFragment = Arrays.copyOfRange(key, 0, 6561); // Get the normalized bundle hash - String normalizedBundleHash = bundle.normalizedBundle(bundleHash); + int[] normalizedBundleHash = bundle.normalizedBundle(bundleHash); // First bundle fragment uses 27 trytes - var firstBundleFragment = normalizedBundleHash(27); + int[] firstBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 0, 27); // Calculate the new signatureFragment with the first bundle fragment - var firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); + int[] firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); // Convert signature to trytes and assign the new signatureFragment - bundle.Transactions[i].signatureMessageFragment = Converter.trytes(firstSignedFragment); + bundle.getTransactions().get(i).setSignatureMessageChunk(Converter.trytes(firstSignedFragment)); // Because the signature is > 2187 trytes, we need to // find the second transaction to add the remainder of the signature - for (var j = 0; j < bundle.Transactions.Count; j++) { + for (int j = 0; j < bundle.getTransactions().size(); j++) { // Same address as well as value = 0 (as we already spent the input) - if (bundle.Transactions[j].Address == thisAddress && bundle.Transactions[j].Value == 0) { + if (bundle.getTransactions().get(j).getAddress() == thisAddress && Long.parseLong(bundle.getTransactions().get(j).getValue()) == 0) { // Use the second 6562 trits - var secondFragment = key.Skip(6561).Take(6561); + int[] secondFragment = Arrays.copyOfRange(key, 6561, 6561 * 2); // The second 27 to 54 trytes of the bundle hash - var secondBundleFragment = normalizedBundleHash.slice(27, 27 * 2); + int[] secondBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 27, 27 * 2); // Calculate the new signature - var secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); + int[] secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); // Convert signature to trytes and assign it again to this bundle entry bundle.getTransactions().get(j).setSignatureMessageChunk(Converter.trytes(secondSignedFragment)); @@ -154,5 +154,5 @@ public class IotaAPIUtils { } Collections.reverse(bundleTrytes); return bundleTrytes; - }*/ + } } diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index a5e2553..a3b2148 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import com.sun.org.apache.xpath.internal.operations.Bool; +import jota.model.Bundle; import jota.pow.Curl; public class Signing { @@ -90,4 +92,101 @@ public class Signing { curl.squeeze(address, 0, address.length); return address; } + + /** + * + * + **/ + public static int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) { + + int[] signatureFragment = keyFragment; + int[] hash; + + Curl curl = new Curl(); + + for (int i = 0; i < 27; i++) { + + hash = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243); + + for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) { + + curl.reset(); + curl.absorb(hash, 0, hash.length); + curl.squeeze(hash, 0, hash.length); + } + + for (int j = 0; j < 243; j++) { + + signatureFragment[i * 243 + j] = hash[j]; + } + } + + return signatureFragment; + } + + /** + * + * + **/ + public static int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) { + + int[] buffer = new int[243]; + + Curl curl = new Curl(); + + curl.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.reset(); + jCurl.absorb(buffer, 0, buffer.length); + jCurl.squeeze(buffer, 0, buffer.length); + } + + curl.absorb(buffer, 0, buffer.length); + } + + curl.squeeze(buffer, 0, buffer.length); + + return buffer; + } + + /** + * + * + **/ + public static Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) { + + Bundle bundle = new Bundle(); + + int[][] normalizedBundleFragments = new int[3][27]; + int[] normalizedBundleHash = bundle.normalizedBundle(bundleHash); + + // Split hash into 3 fragments + for (int i = 0; i < 3; i++) { + normalizedBundleFragments[i] = Arrays.copyOfRange(normalizedBundleHash, i * 27, (i + 1) * 27); + } + + // Get digests + int[] digests = new int[signatureFragments.length * 243 + 243]; + + for (int i = 0; i < signatureFragments.length; i++) { + + int[] digestBuffer = digest(normalizedBundleFragments[i % 3], Converter.trits(signatureFragments[i])); + + for (int j = 0; j < 243; j++) { + + digests[i * 243 + j] = digestBuffer[j]; + } + } + + String address = Converter.trytes(address(digests)); + + return (expectedAddress.equals(address)); + } } From a633a54401f16b9380f3d603344d9bc9c42d24d8 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 20:46:56 +0100 Subject: [PATCH 024/111] [WIP ] tryfix sendTransfer --- src/main/java/jota/IotaAPIProxy.java | 54 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 8319077..dff33f0 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -257,13 +257,7 @@ public class IotaAPIProxy { throw new NotImplementedException("MISSING"); } -/* - public Transaction[] SendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, int[] inputs, String address) { - // todo: check what to do with the optional arguments - String[] trytes = prepareTransfers(seed, transactions, inputs, address); - return sendTrytes(trytes, depth, minWeightMagnitude); - } -*/ + public Inputs getInputs(String seed, Integer start, Integer end, int threshold) throws ArgumentException, NotEnoughBalanceException { if (start == null || start < 0) start = 0; @@ -337,10 +331,15 @@ public class IotaAPIProxy { throw new NotEnoughBalanceException(); } } -/* - public String[] prepareTransfers(String seed, Transfer[] transfers, String[] inputs, String remainderAddress) throws NotEnoughBalanceException,ArgumentException{ - //InputValidator.checkTransferArray(transfers); + + public Transaction[] SendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transfers, Input[] inputs, String address) throws NotEnoughBalanceException, ArgumentException { + String[] trytes = prepareTransfers(seed, transfers, inputs, address); + return sendTrytes(trytes, depth, minWeightMagnitude); + } + + public String[] prepareTransfers(String seed, Transfer[] transfers, Input[] inputs, String remainderAddress) throws NotEnoughBalanceException, ArgumentException { + //InputValidator.checkTransferArray(transfers); // If message or tag is not supplied, provide it for (Transfer transfer : transfers) { @@ -426,8 +425,8 @@ public class IotaAPIProxy { // Get list if addresses of the provided inputs List inputAddresses = new ArrayList(); - for (String input : inputs) { - inputAddresses.add(input); + for (Input input : inputs) { + inputAddresses.add(input.getAddress()); } GetBalancesResponse balances = getBalances(100, inputAddresses.toArray(new String[inputAddresses.size()])); @@ -441,10 +440,9 @@ public class IotaAPIProxy { // If input has balance, add it to confirmedInputs if (thisBalance > 0) { - String inputEl = inputs[i]; - inputEl = thisBalance + ""; - - confirmedInputs.add(new Input()); + Input inputEl = inputs[i]; + inputEl.setBalance(thisBalance); + confirmedInputs.add(inputEl); } } @@ -462,25 +460,25 @@ public class IotaAPIProxy { // If no inputs provided, derive the addresses from the seed and // confirm that the inputs exceed the threshold else { - // todo getInputs should trow an exception if not enough balance - addRemainder(seed, GetInputs(seed, null, null, (int) totalValue).InputsList, - totalValue, bundle, tag, remainderAddress, signatureFragments); + Inputs input = getInputs(seed, null, null, (int) totalValue); + if (input != null && input.getInputsList() != null) { + addRemainder(seed, input.getInputsList(), totalValue, bundle, tag, remainderAddress, signatureFragments); + } else { + throw new NotEnoughBalanceException(); + } } } else { // If no input required, don't sign and simply finalize the bundle bundle.finalize(); bundle.addTrytes(signatureFragments); - List bundleTrytes = null; - // todo not sure what to add here - bundle.getLength().forEach(); - tx =>bundleTrytes.add(null); + List bundleTrytes = new ArrayList<>(); - bundleTrytes.Reverse(); - return bundleTrytes.toArray(); + for (Transaction trx : bundle.getTransactions()) { + bundleTrytes.add(IotaAPIUtils.transactionTrytes(trx)); + } + return bundleTrytes.toArray(new String[bundleTrytes.size()]); } - - // todo not sure what to return here too return null; } @@ -530,7 +528,7 @@ public class IotaAPIProxy { } } } - */ + public static class Builder { From 39c5ed4fa387615dcc14ea8618746f38409bffbc Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 21:40:34 +0100 Subject: [PATCH 025/111] [WIP ] added finalize to bundle --- src/main/java/jota/model/Bundle.java | 40 +++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index f6c7d7a..9f74b9d 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -1,5 +1,6 @@ package jota.model; +import jota.pow.Curl; import jota.utils.Converter; import org.apache.commons.lang3.NotImplementedException; @@ -45,9 +46,46 @@ public class Bundle { } public void finalize() { - throw new NotImplementedException(""); + + Curl curl = new Curl(); + curl.reset(); + + for (int i = 0; i < this.getTransactions().size(); i++) { + + int[] valueTrits = Converter.trits(this.getTransactions().get(i).getValue()); + while (valueTrits.length < 81) { + valueTrits[valueTrits.length] = 0; + } + + int[] timestampTrits = Converter.trits(this.getTransactions().get(i).getTimestamp()); + while (timestampTrits.length < 27) { + timestampTrits[timestampTrits.length] = 0; + } + + int[] currentIndexTrits = Converter.trits(this.getTransactions().get(i).setCurrentIndex("" + i)); + while (currentIndexTrits.length < 27) { + currentIndexTrits[currentIndexTrits.length] = 0; + } + + int[] lastIndexTrits = Converter.trits(this.getTransactions().get(i).setLastIndex("" + (this.getTransactions().size() - 1))); + while (lastIndexTrits.length < 27) { + lastIndexTrits[lastIndexTrits.length] = 0; + } + 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); + + } + + int[] hash = new int[90]; + curl.squeeze(hash, 0, hash.length); + String hashInTrytes = Converter.trytes(hash); + + for (int i = 0; i < this.getTransactions().size(); i++) { + this.getTransactions().get(i).setBundle(hashInTrytes); + } } + public void addTrytes(List signatureFragments) { throw new NotImplementedException(""); } From 26343b2a38ff310c6dd44d5854a48101773e3d78 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 9 Dec 2016 22:46:43 +0100 Subject: [PATCH 026/111] [WIP ] --- src/main/java/jota/IotaAPIProxy.java | 89 +++++++++++++++++++- src/main/java/jota/model/Transaction.java | 12 ++- src/main/java/jota/utils/Converter.java | 45 +++++++++- src/main/java/jota/utils/InputValidator.java | 21 +++++ 4 files changed, 160 insertions(+), 7 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index dff33f0..d8122d5 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -1,10 +1,13 @@ package jota; +import com.sun.org.apache.xpath.internal.Arg; import jota.dto.request.*; import jota.dto.response.*; import jota.error.ArgumentException; import jota.error.NotEnoughBalanceException; import jota.model.*; +import jota.utils.Converter; +import jota.utils.InputValidator; import jota.utils.IotaAPIUtils; import okhttp3.OkHttpClient; import org.apache.commons.lang3.NotImplementedException; @@ -332,8 +335,92 @@ public class IotaAPIProxy { } } + public Bundle[] getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException { + start = start != null ? 0 : start; + end = end == null ? null : end; + inclusionStates = inclusionStates != null ? inclusionStates : null; - public Transaction[] SendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transfers, Input[] inputs, String address) throws NotEnoughBalanceException, ArgumentException { + 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) { + return null; + + Transaction[] trxs = findTransactionObjects(addresses); + // set of tail transactions + var tailTransactions = new Set(); + var nonTailBundleHashes = new Set(); + + transactionObjects.forEach(function(thisTransaction) { + + // Sort tail and nonTails + if (thisTransaction.currentIndex === 0) { + + tailTransactions.add(thisTransaction.hash); + } else { + + nonTailBundleHashes.add(thisTransaction.bundle) + } + }) +/* + // Get tail transactions for each nonTail via the bundle hash + self.findTransactionObjects({'bundles': Array.from(nonTailBundleHashes)}, function(error, bundleObjects) { + + if (error) return callback(error); + + bundleObjects.forEach(function(thisTransaction) { + + if (thisTransaction.currentIndex === 0) { + + tailTransactions.add(thisTransaction.hash); + } + }) + + var finalBundles = []; + var tailTxArray = Array.from(tailTransactions);*/ + } + + public Transaction[] findTransactionObjects(String[] input) throws ArgumentException { + FindTransactionResponse ftr = findTransactions(input, null, null, null); + if (ftr == null || ftr.getHashes() == null) return null; + // get the transaction objects of the transactions + return getTransactionsObjects(ftr.getHashes()); + } + + public Transaction[] getTransactionsObjects(String[] hashes) throws ArgumentException { + + // If not array of hashes, return error + if (!InputValidator.isArrayOfHashes(hashes)) { + throw new ArgumentException(); + } + + // get the trytes of the transaction hashes + GetTrytesResponse gtr = getTrytes(hashes); + if (gtr == null || gtr.getTrytes() == null) return null; + List transactionObjects = new ArrayList<>(); + + // call transactionObjects for each trytes + for (String transactionInTrytes : gtr.getTrytes()) { + + // If no trytes returned, simply push null as placeholder + if (transactionInTrytes == null) { + transactionObjects.add(null); + } else { + transactionObjects.add(Converter.transactionObject(transactionInTrytes)); + } + } + return transactionObjects.toArray(new Transaction[transactionObjects.size()]); + } + + public Transaction[] sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transfers, Input[] inputs, String address) throws NotEnoughBalanceException, ArgumentException { String[] trytes = prepareTransfers(seed, transfers, inputs, address); return sendTrytes(trytes, depth, minWeightMagnitude); } diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index f8f45fa..36140a9 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -20,6 +20,10 @@ public class Transaction { private String branchTransaction; private String nonce; + public Transaction() { + + } + public Transaction(String signatureMessageChunk, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { this.hash = hash; @@ -118,16 +122,16 @@ public class Transaction { return currentIndex; } - public void setCurrentIndex(String currentIndex) { - this.currentIndex = currentIndex; + public String setCurrentIndex(String currentIndex) { + return this.currentIndex = currentIndex; } public String getLastIndex() { return lastIndex; } - public void setLastIndex(String lastIndex) { - this.lastIndex = lastIndex; + public String setLastIndex(String lastIndex) { + return this.lastIndex = lastIndex; } public String getNonce() { diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index c10792b..818fe7b 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -1,5 +1,8 @@ package jota.utils; +import jota.model.Transaction; +import jota.pow.Curl; + import java.util.Arrays; public class Converter { @@ -94,7 +97,7 @@ public class Converter { public static int[] copyTrits(final String input, final int[] destination) { for (int i = 0; i < input.length(); i++) { int index = Constants.TRYTE_ALPHABET.indexOf(input.charAt(i)); - destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS [index][0]; + destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS[index][0]; destination[i * 3 + 1] = TRYTE_TO_TRITS_MAPPINGS[index][1]; destination[i * 3 + 2] = TRYTE_TO_TRITS_MAPPINGS[index][2]; } @@ -130,7 +133,8 @@ public class Converter { for (int i = trits.length; i-- > 0; ) { value = value * 3 + trits[i]; } - return value; } + return value; + } public static void increment(final int[] trits, final int size) { @@ -142,4 +146,41 @@ public class Converter { } } } + + public static Transaction transactionObject(String trytes) { + if (trytes == null) return null; + + // validity check + for (int i = 2279; i < 2295; i++) { + if (trytes.charAt(i) != '9') { + return null; + } + } + int[] transactionTrits = Converter.trits(trytes); + int[] hash = new int[90]; + + Curl curl = new Curl(); + + // generate the correct transaction hash + curl.reset(); + curl.absorb(transactionTrits, 0, transactionTrits.length); + curl.squeeze(hash, 0, hash.length); + + Transaction trx = new Transaction(); + + trx.setHash(Converter.trytes(hash)); + trx.setSignatureMessageChunk(trytes.substring(0, 2187)); + trx.setAddress(trytes.substring(2187, 2268)); + trx.setValue("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6804, 6837))); + trx.setTag(trytes.substring(2295, 2322)); + trx.setTimestamp("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6966, 6993))); + trx.setCurrentIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6993, 7020))); + trx.setLastIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 7020, 7047))); + trx.setBundle(trytes.substring(2349, 2430)); + trx.setTrunkTransaction(trytes.substring(2430, 2511)); + trx.setBranchTransaction(trytes.substring(2511, 2592)); + trx.setNonce(trytes.substring(2592, 2673)); + + return trx; + } } \ No newline at end of file diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index c1ddd2a..bddfff7 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -20,4 +20,25 @@ public class InputValidator { public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } + + public static boolean isArrayOfHashes(String[] hashes) { + if (hashes == null) return false; + + for (int i = 0; i < hashes.length; i++) { + String hash = hashes[i]; + + // Check if address with checksum + if (hash.length() == 90) { + if (!isTrytes(hash, 90)) { + return false; + } + } else { + if (!isTrytes(hash, 81)) { + return false; + } + } + } + return true; + + } } From 264857d91c0d25e58fe8a606998da823142790a2 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 10 Dec 2016 08:12:18 +0100 Subject: [PATCH 027/111] [WIP] --- src/main/java/jota/model/Bundle.java | 36 ++++++++++++++++++++++-- src/main/java/jota/model/Input.java | 2 +- src/main/java/jota/model/Transfer.java | 9 ++++++ src/test/java/jota/IotaAPIProxyTest.java | 7 +++++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 9f74b9d..a814d5d 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -42,7 +42,18 @@ public class Bundle { } public void addEntry(int signatureMessageLength, String slice, long value, String tag, long timestamp) { - throw new NotImplementedException(""); + for (int i = 0; i < signatureMessageLength; i++) { + //TODO + +/* var transactionObject = new Object(); + transactionObject.address = address; + transactionObject.value = i == 0 ? value : 0; + transactionObject.tag = tag; + transactionObject.timestamp = timestamp; + + this.bundle[this.bundle.length] = transactionObject; +*/ + } } public void finalize() { @@ -87,7 +98,28 @@ public class Bundle { public void addTrytes(List signatureFragments) { - throw new NotImplementedException(""); + String emptySignatureFragment = ""; + String emptyHash = "999999999999999999999999999999999999999999999999999999999999999999999999999999999"; + + for (int j = 0; emptySignatureFragment.length() < 2187; j++) { + emptySignatureFragment += '9'; + } + + for (int i = 0; i < this.getTransactions().size(); i++) { + + // Fill empty signatureMessageFragment + + //TODO + ///this.getTransactions().get(i).signatureMessageFragment(signatureFragments[i] ? signatureFragments[i] : emptySignatureFragment); + // Fill empty trunkTransaction + this.getTransactions().get(i).setTrunkTransaction(emptyHash); + + // Fill empty branchTransaction + this.getTransactions().get(i).setBranchTransaction(emptyHash); + + // Fill empty nonce + this.getTransactions().get(i).setNonce(emptyHash); + } } public int[] normalizedBundle(String bundleHash) { diff --git a/src/main/java/jota/model/Input.java b/src/main/java/jota/model/Input.java index 8e3a53e..16ce445 100644 --- a/src/main/java/jota/model/Input.java +++ b/src/main/java/jota/model/Input.java @@ -45,4 +45,4 @@ public class Input { public void setKeyIndex(int keyIndex) { this.keyIndex = keyIndex; } -} +} \ No newline at end of file diff --git a/src/main/java/jota/model/Transfer.java b/src/main/java/jota/model/Transfer.java index 06080e2..dabbf6e 100644 --- a/src/main/java/jota/model/Transfer.java +++ b/src/main/java/jota/model/Transfer.java @@ -29,6 +29,15 @@ public class Transfer { } + public Transfer(String address, long value, String message, String tag) { + + this.address = address; + this.value = value; + this.message = message; + this.tag = tag; + + } + @Override public String toString() { return new Gson().toJson(this); diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index ff912f9..82de74e 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -6,6 +6,7 @@ import jota.dto.response.*; import jota.error.ArgumentException; import jota.error.NotEnoughBalanceException; import jota.model.Inputs; +import jota.model.Transfer; import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Before; @@ -32,6 +33,7 @@ public class IotaAPIProxyTest { private static final String TEST_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; private static final String TEST_MILESTONE = "SMYMAKKPSUKCKDRUEYCGZJTYCZ9HHDMDUWBAPXARGURPQRHTAJDASRWMIDTPTBNDKDEFBUTBGGAFX9999"; private static final Integer TEST_MILESTONE_INDEX = 8059; + private static Transfer transfer = new Transfer(TEST_ADDRESS_WITH_CHECKSUM,0, "JAVALIB","JAVA"); private IotaAPIProxy proxy; @@ -141,4 +143,9 @@ public class IotaAPIProxyTest { final Inputs res = proxy.getInputs(TEST_SEED, 0, 1, 1); assertTrue(res.getTotalBalance() > 0); } + + @Test + public void shouldSendTransfer() throws ArgumentException, NotEnoughBalanceException { + proxy.sendTransfer(TEST_SEED,1,13, new Transfer[]{transfer}, null, null); + } } \ No newline at end of file From ffea691e02cc2ee28731993202f90fd113e529ea Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 10 Dec 2016 10:40:23 +0100 Subject: [PATCH 028/111] [WIP] --- src/main/java/jota/model/Bundle.java | 12 +-- src/main/java/jota/model/Transaction.java | 95 +++++++++++----------- src/main/java/jota/utils/Converter.java | 2 +- src/main/java/jota/utils/IotaAPIUtils.java | 6 +- 4 files changed, 57 insertions(+), 58 deletions(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index a814d5d..49bb067 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -1,11 +1,10 @@ package jota.model; import jota.pow.Curl; +import jota.utils.Constants; import jota.utils.Converter; -import org.apache.commons.lang3.NotImplementedException; import java.util.ArrayList; -import java.util.Date; import java.util.List; /** @@ -16,6 +15,9 @@ public class Bundle { private List transactions; private int length; + public static String EMPTY_HASH = "999999999999999999999999999999999999999999999999999999999999999999999999999999999"; + + public Bundle() { this(new ArrayList(), 0); } @@ -99,7 +101,7 @@ public class Bundle { public void addTrytes(List signatureFragments) { String emptySignatureFragment = ""; - String emptyHash = "999999999999999999999999999999999999999999999999999999999999999999999999999999999"; + String emptyHash = EMPTY_HASH; for (int j = 0; emptySignatureFragment.length() < 2187; j++) { emptySignatureFragment += '9'; @@ -108,9 +110,7 @@ public class Bundle { for (int i = 0; i < this.getTransactions().size(); i++) { // Fill empty signatureMessageFragment - - //TODO - ///this.getTransactions().get(i).signatureMessageFragment(signatureFragments[i] ? signatureFragments[i] : emptySignatureFragment); + this.getTransactions().get(i).setSignatureFragments(signatureFragments.get(i) == null ? signatureFragments.get(i) : emptySignatureFragment); // Fill empty trunkTransaction this.getTransactions().get(i).setTrunkTransaction(emptyHash); diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 36140a9..9a19ed3 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.builder.ToStringStyle; */ public class Transaction { private String hash; - private String signatureMessageChunk; + private String signatureFragments; private String address; private String value; private String tag; @@ -24,11 +24,11 @@ public class Transaction { } - public Transaction(String signatureMessageChunk, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { + public Transaction(String signatureFragments, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { this.hash = hash; this.tag = tag; - this.signatureMessageChunk = signatureMessageChunk; + this.signatureFragments = signatureFragments; this.address = address; this.value = value; this.timestamp = timestamp; @@ -45,69 +45,36 @@ public class Transaction { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); } - public void setSignatureMessageChunk(String signatureMessageChunk) { - - this.signatureMessageChunk = signatureMessageChunk; + public String getHash() { + return hash; } public void setHash(String hash) { this.hash = hash; } - public void setTimestamp(String timestamp) { - this.timestamp = timestamp; + public String getSignatureFragments() { + return signatureFragments; } - public void setTrunkTransaction(String trunkTransaction) { - this.trunkTransaction = trunkTransaction; - } - - public void setBranchTransaction(String branchTransaction) { - this.branchTransaction = branchTransaction; - } - - public void setAddress(String address) { - this.address = address; - } - - public void setValue(String value) { - this.value = value; - } - - public void setBundle(String bundle) { - this.bundle = bundle; - } - - public String getValue() { - return value; - } - - public String getTrunkTransaction() { - return trunkTransaction; - } - - public String getTimestamp() { - return timestamp; + public String setSignatureFragments(String signatureFragments) { + return this.signatureFragments = signatureFragments; } public String getAddress() { return address; } - public String getBranchTransaction() { - return branchTransaction; + public void setAddress(String address) { + this.address = address; } - public String getBundle() { - return bundle; + public String getValue() { + return value; } - public String getHash() { - return hash; - } - - public String getSignatureMessageChunk() { - return signatureMessageChunk; + public void setValue(String value) { + this.value = value; } public String getTag() { @@ -118,6 +85,14 @@ public class Transaction { this.tag = tag; } + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + public String getCurrentIndex() { return currentIndex; } @@ -134,6 +109,30 @@ public class Transaction { return this.lastIndex = lastIndex; } + public String getBundle() { + return bundle; + } + + public void setBundle(String bundle) { + this.bundle = bundle; + } + + public String getTrunkTransaction() { + return trunkTransaction; + } + + public void setTrunkTransaction(String trunkTransaction) { + this.trunkTransaction = trunkTransaction; + } + + public String getBranchTransaction() { + return branchTransaction; + } + + public void setBranchTransaction(String branchTransaction) { + this.branchTransaction = branchTransaction; + } + public String getNonce() { return nonce; } diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 818fe7b..4bdf59a 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -169,7 +169,7 @@ public class Converter { Transaction trx = new Transaction(); trx.setHash(Converter.trytes(hash)); - trx.setSignatureMessageChunk(trytes.substring(0, 2187)); + trx.setSignatureFragments(trytes.substring(0, 2187)); trx.setAddress(trytes.substring(2187, 2268)); trx.setValue("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6804, 6837))); trx.setTag(trytes.substring(2295, 2322)); diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 6f24a9d..7fd9c85 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -69,7 +69,7 @@ public class IotaAPIUtils { lastIndexTrits[lastIndexTrits.length] = 0; } - return trx.getSignatureMessageChunk() + return trx.getSignatureFragments() + trx.getAddress() + Converter.trytes(valueTrits) + trx.getTag() @@ -123,7 +123,7 @@ public class IotaAPIUtils { int[] firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); // Convert signature to trytes and assign the new signatureFragment - bundle.getTransactions().get(i).setSignatureMessageChunk(Converter.trytes(firstSignedFragment)); + bundle.getTransactions().get(i).setSignatureFragments(Converter.trytes(firstSignedFragment)); // Because the signature is > 2187 trytes, we need to // find the second transaction to add the remainder of the signature @@ -140,7 +140,7 @@ public class IotaAPIUtils { int[] secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); // Convert signature to trytes and assign it again to this bundle entry - bundle.getTransactions().get(j).setSignatureMessageChunk(Converter.trytes(secondSignedFragment)); + bundle.getTransactions().get(j).setSignatureFragments(Converter.trytes(secondSignedFragment)); } } } From 3868faaf4036eb61eea039d0d3214c6ce9d7bb2d Mon Sep 17 00:00:00 2001 From: AZ Date: Sat, 10 Dec 2016 18:44:28 +0100 Subject: [PATCH 029/111] bundlesfromaddresses and latestinclusion added --- src/main/java/jota/IotaAPIProxy.java | 86 ++++++++++++++++------- src/main/java/jota/model/Transaction.java | 9 +++ src/main/java/jota/model/Transfer.java | 33 ++++++++- 3 files changed, 100 insertions(+), 28 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index d8122d5..bf65728 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -351,41 +351,75 @@ public class IotaAPIProxy { return null; } - public Bundle[] bundlesFromAddresses(String[] addresses, Boolean inclusionStates) { - return null; + public Bundle[] bundlesFromAddresses(String[] addresses, Boolean inclusionStates) throws ArgumentException { Transaction[] trxs = findTransactionObjects(addresses); // set of tail transactions - var tailTransactions = new Set(); - var nonTailBundleHashes = new Set(); - - transactionObjects.forEach(function(thisTransaction) { + List tailTransactions = new ArrayList<>(); + List nonTailBundleHashes = new ArrayList<>(); + for (Transaction trx : trxs) { // Sort tail and nonTails - if (thisTransaction.currentIndex === 0) { - - tailTransactions.add(thisTransaction.hash); + if (Long.parseLong(trx.getCurrentIndex()) == 0) { + tailTransactions.add(trx.getHash()); } else { - - nonTailBundleHashes.add(thisTransaction.bundle) + nonTailBundleHashes.add(trx.getBundle()); } - }) -/* - // Get tail transactions for each nonTail via the bundle hash - self.findTransactionObjects({'bundles': Array.from(nonTailBundleHashes)}, function(error, bundleObjects) { + } + if (nonTailBundleHashes.isEmpty()) return null; - if (error) return callback(error); + Transaction[] bundleObjects = findTransactionObjects(addresses); + for (Transaction trx : bundleObjects) { + // Sort tail and nonTails + if (Long.parseLong(trx.getCurrentIndex()) == 0) { + tailTransactions.add(trx.getHash()); + } + } - bundleObjects.forEach(function(thisTransaction) { + List finalBundles = new ArrayList<>(); + String[] tailTxArray = tailTransactions.toArray(new String[tailTransactions.size()]); - if (thisTransaction.currentIndex === 0) { - - tailTransactions.add(thisTransaction.hash); + // 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) { + GetBundleResponse 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(GetBundleResponse c1, GetBundleResponse 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; + } - var finalBundles = []; - var tailTxArray = Array.from(tailTransactions);*/ + public GetInclusionStateResponse getLatestInclusion(String[] hashes) { + GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); + if (getNodeInfoResponse == null) return null; + + String[] latestMilestone = {getNodeInfoResponse.getLatestSolidSubtangleMilestone()}; + + return getInclusionStates(hashes, latestMilestone); } public Transaction[] findTransactionObjects(String[] input) throws ArgumentException { @@ -420,12 +454,14 @@ public class IotaAPIProxy { return transactionObjects.toArray(new Transaction[transactionObjects.size()]); } - public Transaction[] sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transfers, Input[] inputs, String address) throws NotEnoughBalanceException, ArgumentException { + public Transaction[] sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transfers, Input[] + inputs, String address) throws NotEnoughBalanceException, ArgumentException { String[] trytes = prepareTransfers(seed, transfers, inputs, address); return sendTrytes(trytes, depth, minWeightMagnitude); } - public String[] prepareTransfers(String seed, Transfer[] transfers, Input[] inputs, String remainderAddress) throws NotEnoughBalanceException, ArgumentException { + public String[] prepareTransfers(String seed, Transfer[] transfers, Input[] inputs, String remainderAddress) throws + NotEnoughBalanceException, ArgumentException { //InputValidator.checkTransferArray(transfers); // If message or tag is not supplied, provide it diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 9a19ed3..c67bf53 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -19,6 +19,7 @@ public class Transaction { private String trunkTransaction; private String branchTransaction; private String nonce; + private Boolean persistence; public Transaction() { @@ -140,4 +141,12 @@ public class Transaction { public void setNonce(String nonce) { this.nonce = nonce; } + + public Boolean getPersistence() { + return persistence; + } + + public void setPersistence(Boolean persistence) { + this.persistence = persistence; + } } diff --git a/src/main/java/jota/model/Transfer.java b/src/main/java/jota/model/Transfer.java index dabbf6e..4fdaa8c 100644 --- a/src/main/java/jota/model/Transfer.java +++ b/src/main/java/jota/model/Transfer.java @@ -12,12 +12,12 @@ public class Transfer { private String timestamp; private String address; private String hash; - private Integer persistence; + private Boolean persistence; private long value; private String message; private String tag; - public Transfer(String timestamp, String address, String hash, Integer persistence, long value, String message, String tag) { + public Transfer(String timestamp, String address, String hash, Boolean persistence, long value, String message, String tag) { this.timestamp = timestamp; this.address = address; @@ -51,7 +51,7 @@ public class Transfer { return hash; } - public Integer getPersistence() { + public Boolean getPersistence() { return persistence; } @@ -71,4 +71,31 @@ public class Transfer { return tag; } + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public void setAddress(String address) { + this.address = address; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public void setPersistence(Boolean persistence) { + this.persistence = persistence; + } + + public void setValue(long value) { + this.value = value; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setTag(String tag) { + this.tag = tag; + } } From 21ddac09d0b93078493ab3ce0408e50a577edaa2 Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Wed, 14 Dec 2016 11:06:06 +0100 Subject: [PATCH 030/111] updated and added new Utils (#9) * added SeedRandomGenerator * extended IotaUnitConverter * minor * added isArrayOfHashes * renamed constants * added error package * added transactionObject * fixed IotaUnitConverter --- .../java/jota/error/ArgumentException.java | 10 ++ src/main/java/jota/error/BaseException.java | 51 +++++++ .../jota/error/NotEnoughBalanceException.java | 10 ++ src/main/java/jota/model/Transaction.java | 141 ++++++++++++------ src/main/java/jota/utils/Checksum.java | 4 +- src/main/java/jota/utils/Constants.java | 6 +- src/main/java/jota/utils/Converter.java | 63 +++++++- src/main/java/jota/utils/InputValidator.java | 22 ++- .../java/jota/utils/IotaUnitConverter.java | 53 ++++++- .../java/jota/utils/SeedRandomGenerator.java | 20 +++ src/main/java/jota/utils/TrytesConverter.java | 8 +- src/test/java/jota/IotaUnitConverterTest.java | 20 +++ .../java/jota/SeedRandomGeneratorTest.java | 22 +++ 13 files changed, 368 insertions(+), 62 deletions(-) create mode 100644 src/main/java/jota/error/ArgumentException.java create mode 100644 src/main/java/jota/error/BaseException.java create mode 100644 src/main/java/jota/error/NotEnoughBalanceException.java create mode 100644 src/main/java/jota/utils/SeedRandomGenerator.java create mode 100644 src/test/java/jota/SeedRandomGeneratorTest.java diff --git a/src/main/java/jota/error/ArgumentException.java b/src/main/java/jota/error/ArgumentException.java new file mode 100644 index 0000000..759b694 --- /dev/null +++ b/src/main/java/jota/error/ArgumentException.java @@ -0,0 +1,10 @@ +package jota.error; + +/** + * Created by Adrian on 09.12.2016. + */ +public class ArgumentException extends BaseException { + public ArgumentException() { + super("wrong arguments passed to function"); + } +} diff --git a/src/main/java/jota/error/BaseException.java b/src/main/java/jota/error/BaseException.java new file mode 100644 index 0000000..b1eb210 --- /dev/null +++ b/src/main/java/jota/error/BaseException.java @@ -0,0 +1,51 @@ +package jota.error; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * Created by Adrian on 09.12.2016. + */ +public class BaseException extends Exception { + protected Collection messages; + + public BaseException(String msg) { + super(msg); + } + + + public BaseException(String msg, Exception cause) { + super(msg, cause); + } + + + public BaseException(Collection messages) { + super(); + this.messages = messages; + } + + + public BaseException(Collection messages, Exception cause) { + super(cause); + this.messages = messages; + } + + @Override + public String getMessage() { + String msg; + + if (this.messages != null && !this.messages.isEmpty()) { + msg = "["; + + for (String message : this.messages) { + msg += message + ","; + } + + msg = StringUtils.removeEnd(msg, ",") + "]"; + + } else msg = super.getMessage(); + + return msg; + } +} diff --git a/src/main/java/jota/error/NotEnoughBalanceException.java b/src/main/java/jota/error/NotEnoughBalanceException.java new file mode 100644 index 0000000..c7099d6 --- /dev/null +++ b/src/main/java/jota/error/NotEnoughBalanceException.java @@ -0,0 +1,10 @@ +package jota.error; + +/** + * Created by Adrian on 09.12.2016. + */ +public class NotEnoughBalanceException extends BaseException { + public NotEnoughBalanceException() { + super("not enough balance dude"); + } +} diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 4cf5e89..8a74f5a 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -7,36 +7,38 @@ import org.apache.commons.lang3.builder.ToStringStyle; * Created by pinpong on 02.12.16. */ public class Transaction { - - private String signatureMessageChunk; - private String index; - private String approvalNonce; private String hash; - private String digest; - private String type; - private String timestamp; - private String trunkTransaction; - private String branchTransaction; - private String signatureNonce; + private String signatureFragments; private String address; private String value; + private String tag; + private String timestamp; + private String currentIndex; + private String lastIndex; private String bundle; + private String trunkTransaction; + private String branchTransaction; + private String nonce; + private Boolean persistence; - public Transaction(String signatureMessageChunk, String index, String approvalNonce, String hash, String digest, String type, String timestamp, String trunkTransaction, String branchTransaction, String signatureNonce, String address, String value, String bundle) { + public Transaction() { + + } + + public Transaction(String signatureFragments, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { this.hash = hash; - this.type = type; - this.signatureMessageChunk = signatureMessageChunk; - this.digest = digest; + this.tag = tag; + this.signatureFragments = signatureFragments; this.address = address; this.value = value; this.timestamp = timestamp; - this.index = index; + this.currentIndex = currentIndex; + this.lastIndex = lastIndex; this.bundle = bundle; - this.signatureNonce = signatureNonce; - this.approvalNonce = approvalNonce; this.trunkTransaction = trunkTransaction; this.branchTransaction = branchTransaction; + this.nonce = nonce; } @Override @@ -44,56 +46,107 @@ public class Transaction { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); } - public String getValue() { - return value; + public String getHash() { + return hash; } - public String getDigest() { - return digest; + public void setHash(String hash) { + this.hash = hash; } - public String getTrunkTransaction() { - return trunkTransaction; + public String getSignatureFragments() { + return signatureFragments; } - public String getTimestamp() { - return timestamp; - } - - public String getSignatureNonce() { - return signatureNonce; - } - - public String getType() { - return type; + public String setSignatureFragments(String signatureFragments) { + return this.signatureFragments = signatureFragments; } public String getAddress() { return address; } - public String getApprovalNonce() { - return approvalNonce; + public void setAddress(String address) { + this.address = address; } - public String getBranchTransaction() { - return branchTransaction; + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getCurrentIndex() { + return currentIndex; + } + + public String setCurrentIndex(String currentIndex) { + return this.currentIndex = currentIndex; + } + + public String getLastIndex() { + return lastIndex; + } + + public String setLastIndex(String lastIndex) { + return this.lastIndex = lastIndex; } public String getBundle() { return bundle; } - public String getHash() { - return hash; + public void setBundle(String bundle) { + this.bundle = bundle; } - public String getIndex() { - return index; + public String getTrunkTransaction() { + return trunkTransaction; } - public String getSignatureMessageChunk() { - return signatureMessageChunk; + public void setTrunkTransaction(String trunkTransaction) { + this.trunkTransaction = trunkTransaction; } -} + public String getBranchTransaction() { + return branchTransaction; + } + + public void setBranchTransaction(String branchTransaction) { + this.branchTransaction = branchTransaction; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public Boolean getPersistence() { + return persistence; + } + + public void setPersistence(Boolean persistence) { + this.persistence = persistence; + } +} \ No newline at end of file diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index fe22f5a..6bf83f5 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -24,7 +24,7 @@ public class Checksum { } private static String getAddress(String addressWithChecksum) { - return addressWithChecksum.substring(0, Constants.addressLengthWithoutChecksum); + return addressWithChecksum.substring(0, Constants.ADDRESS_LENGTH_WITHOUT_CHECKSUM); } public static boolean isValidChecksum(String addressWithChecksum) { @@ -34,7 +34,7 @@ public class Checksum { } private static boolean isAddressWithChecksum(String addressWithChecksum) { - return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.addressLengthWithChecksum; + return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.ADDRESS_LENGTH_WITH_CHECKSUM; } public static String calculateChecksum(String address) { diff --git a/src/main/java/jota/utils/Constants.java b/src/main/java/jota/utils/Constants.java index 997b296..2b9d4a5 100644 --- a/src/main/java/jota/utils/Constants.java +++ b/src/main/java/jota/utils/Constants.java @@ -7,7 +7,9 @@ public class Constants { public static final String TRYTE_ALPHABET = "9ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public static int addressLengthWithoutChecksum = 81; - public static int addressLengthWithChecksum = 90; + public static final int SEED_LENGTH_MAX = 81; + + public static int ADDRESS_LENGTH_WITHOUT_CHECKSUM = 81; + public static int ADDRESS_LENGTH_WITH_CHECKSUM = 90; } diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index a43388f..0a94107 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -1,16 +1,19 @@ package jota.utils; +import jota.model.Transaction; +import jota.pow.Curl; + import java.util.Arrays; public class Converter { - public static final int RADIX = 3; - public static final int MAX_TRIT_VALUE = (RADIX - 1) / 2, MIN_TRIT_VALUE = -MAX_TRIT_VALUE; + private static final int RADIX = 3; + private static final int MAX_TRIT_VALUE = (RADIX - 1) / 2, MIN_TRIT_VALUE = -MAX_TRIT_VALUE; - public static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; - public static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; - static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; - static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; + private static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; + private static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; + private static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; + private static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; static { @@ -94,7 +97,7 @@ public class Converter { public static int[] copyTrits(final String input, final int[] destination) { for (int i = 0; i < input.length(); i++) { int index = Constants.TRYTE_ALPHABET.indexOf(input.charAt(i)); - destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS [index][0]; + destination[i * 3] = TRYTE_TO_TRITS_MAPPINGS[index][0]; destination[i * 3 + 1] = TRYTE_TO_TRITS_MAPPINGS[index][1]; destination[i * 3 + 2] = TRYTE_TO_TRITS_MAPPINGS[index][2]; } @@ -124,6 +127,15 @@ public class Converter { return trits[offset] + trits[offset + 1] * 3 + trits[offset + 2] * 9; } + public static int value(final int[] trits) { + int value = 0; + + for (int i = trits.length; i-- > 0; ) { + value = value * 3 + trits[i]; + } + return value; + } + public static void increment(final int[] trits, final int size) { for (int i = 0; i < size; i++) { @@ -134,4 +146,41 @@ public class Converter { } } } + + public static Transaction transactionObject(String trytes) { + if (trytes == null) return null; + + // validity check + for (int i = 2279; i < 2295; i++) { + if (trytes.charAt(i) != '9') { + return null; + } + } + int[] transactionTrits = Converter.trits(trytes); + int[] hash = new int[90]; + + Curl curl = new Curl(); + + // generate the correct transaction hash + curl.reset(); + curl.absorb(transactionTrits, 0, transactionTrits.length); + curl.squeeze(hash, 0, hash.length); + + Transaction trx = new Transaction(); + + trx.setHash(Converter.trytes(hash)); + trx.setSignatureFragments(trytes.substring(0, 2187)); + trx.setAddress(trytes.substring(2187, 2268)); + trx.setValue("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6804, 6837))); + trx.setTag(trytes.substring(2295, 2322)); + trx.setTimestamp("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6966, 6993))); + trx.setCurrentIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6993, 7020))); + trx.setLastIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 7020, 7047))); + trx.setBundle(trytes.substring(2349, 2430)); + trx.setTrunkTransaction(trytes.substring(2430, 2511)); + trx.setBranchTransaction(trytes.substring(2511, 2592)); + trx.setNonce(trytes.substring(2592, 2673)); + + return trx; + } } \ No newline at end of file diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index c1ddd2a..d658bd3 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -6,8 +6,8 @@ package jota.utils; public class InputValidator { public static boolean isAddress(String address) { - return (address.length() == Constants.addressLengthWithoutChecksum || - address.length() == Constants.addressLengthWithChecksum) && isTrytes(address, address.length()); + return (address.length() == Constants.ADDRESS_LENGTH_WITHOUT_CHECKSUM || + address.length() == Constants.ADDRESS_LENGTH_WITH_CHECKSUM) && isTrytes(address, address.length()); } public static boolean checkAddress(String address) { @@ -20,4 +20,22 @@ public class InputValidator { public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } + + public static boolean isArrayOfHashes(String[] hashes) { + if (hashes == null) return false; + + for (String hash : hashes) { + // Check if address with checksum + if (hash.length() == 90) { + if (!isTrytes(hash, 90)) { + return false; + } + } else { + if (!isTrytes(hash, 81)) { + return false; + } + } + } + return true; + } } diff --git a/src/main/java/jota/utils/IotaUnitConverter.java b/src/main/java/jota/utils/IotaUnitConverter.java index 57271e8..cdd4529 100644 --- a/src/main/java/jota/utils/IotaUnitConverter.java +++ b/src/main/java/jota/utils/IotaUnitConverter.java @@ -1,7 +1,9 @@ package jota.utils; +import java.text.DecimalFormat; + /** - * Created by pinpong on 30.11.16. + * Created by Sascha on 30.11.16. */ public class IotaUnitConverter { @@ -13,4 +15,53 @@ public class IotaUnitConverter { private static long convertUnits(long amount, IotaUnits toUnit) { return (long) (amount / Math.pow(10, toUnit.getValue())); } + + public static String convertRawIotaAmountToDisplayText(long amount) { + IotaUnits unit = findOptimalIotaUnitToDisplay(amount); + double amountInDisplayUnit = convertAmountTo(amount, unit); + return createAmountWithUnitDisplayText(amountInDisplayUnit, unit); + } + + public static double convertAmountTo(long amount, IotaUnits target) { + return amount / Math.pow(10, target.getValue()); + } + + private static String createAmountWithUnitDisplayText(double amountInUnit, IotaUnits unit) { + String result = createAmountDisplayText(amountInUnit, unit); + result += " " + unit.getUnit(); + return result; + } + + public static String createAmountDisplayText(double amountInUnit, IotaUnits unit) { + DecimalFormat df = new DecimalFormat("##0.##################"); + String result = ""; + // display unit as integer if value is between 1-999 or in decimal format + result += unit == IotaUnits.IOTA ? (long) amountInUnit : df.format(amountInUnit); + return result; + } + + public static IotaUnits findOptimalIotaUnitToDisplay(long amount) { + int length = String.valueOf(amount).length(); + + if (amount < 0) // do not count "-" sign + length -= 1; + + IotaUnits units = IotaUnits.IOTA; + + if (length >= 1 && length <= 3) { + units = IotaUnits.IOTA; + } else if (length > 3 && length <= 6) { + units = IotaUnits.KILO_IOTA; + } else if (length > 6 && length <= 9) { + units = IotaUnits.MEGA_IOTA; + } else if (length > 9 && length <= 12) { + units = IotaUnits.GIGA_IOTA; + } else if (length > 12 && length <= 15) { + units = IotaUnits.TERA_IOTA; + } else if (length > 15 && length <= 18) { + units = IotaUnits.PETA_IOTA; + } + return units; + } + } diff --git a/src/main/java/jota/utils/SeedRandomGenerator.java b/src/main/java/jota/utils/SeedRandomGenerator.java new file mode 100644 index 0000000..8e702cb --- /dev/null +++ b/src/main/java/jota/utils/SeedRandomGenerator.java @@ -0,0 +1,20 @@ +package jota.utils; + +import java.util.Random; + +/** + * Created by pinpong on 13.12.16. + */ +public class SeedRandomGenerator { + + public static String generateNewSeed() { + char[] chars = Constants.TRYTE_ALPHABET.toCharArray(); + StringBuilder builder = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < Constants.SEED_LENGTH_MAX; i++) { + char c = chars[random.nextInt(chars.length)]; + builder.append(c); + } + return builder.toString(); + } +} diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java index 21f560e..5c5d843 100644 --- a/src/main/java/jota/utils/TrytesConverter.java +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -70,7 +70,7 @@ public class TrytesConverter { public static String toString(String inputTrytes) { - String string = ""; + StringBuilder string = new StringBuilder(); for (int i = 0; i < inputTrytes.length(); i += 2) { // get a trytes pair @@ -82,9 +82,9 @@ public class TrytesConverter { String character = Character.toString((char) decimalValue); - string += character; + string.append(character); } - return string; + return string.toString(); } -} +} \ No newline at end of file diff --git a/src/test/java/jota/IotaUnitConverterTest.java b/src/test/java/jota/IotaUnitConverterTest.java index 5078ac5..81da852 100644 --- a/src/test/java/jota/IotaUnitConverterTest.java +++ b/src/test/java/jota/IotaUnitConverterTest.java @@ -35,4 +35,24 @@ public class IotaUnitConverterTest { public void shouldConvertUnitTiToPi() { assertEquals(IotaUnitConverter.convertUnits(1000, IotaUnits.TERA_IOTA, IotaUnits.PETA_IOTA), 1); } + + @Test + public void shouldFindOptimizeUnitToDisplay() { + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1), IotaUnits.IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000), IotaUnits.KILO_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000), IotaUnits.MEGA_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000000), IotaUnits.GIGA_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000000000L), IotaUnits.TERA_IOTA); + assertEquals(IotaUnitConverter.findOptimalIotaUnitToDisplay(1000000000000000L), IotaUnits.PETA_IOTA); + } + + @Test + public void shouldConvertRawIotaAmountToDisplayText() { + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1), "1 i"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000), "1 Ki"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000), "1 Mi" ); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000), "1 Gi" ); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000000L), "1 Ti"); + assertEquals(IotaUnitConverter.convertRawIotaAmountToDisplayText(1000000000000000L), "1 Pi"); + } } diff --git a/src/test/java/jota/SeedRandomGeneratorTest.java b/src/test/java/jota/SeedRandomGeneratorTest.java new file mode 100644 index 0000000..b2ab6d2 --- /dev/null +++ b/src/test/java/jota/SeedRandomGeneratorTest.java @@ -0,0 +1,22 @@ +package jota; + +import jota.utils.Constants; +import jota.utils.InputValidator; +import jota.utils.SeedRandomGenerator; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Created by pinpong on 13.12.16. + */ +public class SeedRandomGeneratorTest { + + @Test + public void shouldGenerateNewSeed() { + + String generatedSeed = SeedRandomGenerator.generateNewSeed(); + assertEquals(InputValidator.isAddress(generatedSeed), true); + assertEquals(generatedSeed.length(), Constants.SEED_LENGTH_MAX); + } +} From b38e828dc293b861934cab50a7d95682bdad55d4 Mon Sep 17 00:00:00 2001 From: Gianluigi Davassi Date: Thu, 15 Dec 2016 11:23:04 +0100 Subject: [PATCH 031/111] updating (#10) From 548b311eedba40b4e971eb7efd7b1ca216cb3966 Mon Sep 17 00:00:00 2001 From: Gianluigi Davassi Date: Fri, 16 Dec 2016 16:01:28 +0100 Subject: [PATCH 032/111] Merging (#11) * added SeedRandomGenerator * extended IotaUnitConverter * minor * added isArrayOfHashes * renamed constants * added error package * added transactionObject * fixed IotaUnitConverter From 937a2b2e38a95d8b07fadf3affffb44e4b180cae Mon Sep 17 00:00:00 2001 From: davassi Date: Sun, 18 Dec 2016 12:33:26 +0100 Subject: [PATCH 033/111] Implemented broadcastAndStore and sendTrytes --- src/main/java/jota/IotaAPIProxy.java | 72 +++++++- .../java/jota/error/ArgumentException.java | 5 +- src/main/java/jota/error/BaseException.java | 25 +-- .../jota/error/NotEnoughBalanceException.java | 5 +- src/main/java/jota/model/Bundle.java | 162 ++++++++++++++++++ src/main/java/jota/model/Input.java | 48 ++++++ src/main/java/jota/pow/Curl.java | 46 ++--- src/main/java/jota/utils/Constants.java | 1 - src/main/java/jota/utils/Converter.java | 25 ++- src/main/java/jota/utils/IotaAPIUtils.java | 119 ++++++++++++- .../java/jota/utils/IotaUnitConverter.java | 3 +- src/main/java/jota/utils/IotaUnits.java | 1 + .../java/jota/utils/SeedRandomGenerator.java | 4 +- src/main/java/jota/utils/Signing.java | 26 ++- src/main/java/jota/utils/TrytesConverter.java | 15 +- src/test/java/jota/SendMessageTest.java | 12 ++ src/test/java/jota/TrytesConverterTest.java | 12 ++ teststore.txt | 1 + 18 files changed, 514 insertions(+), 68 deletions(-) create mode 100644 src/main/java/jota/model/Bundle.java create mode 100644 src/main/java/jota/model/Input.java create mode 100644 src/test/java/jota/SendMessageTest.java create mode 100644 teststore.txt diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 5ce6806..8901c71 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -2,6 +2,8 @@ package jota; import jota.dto.request.*; import jota.dto.response.*; +import jota.model.Transaction; +import jota.utils.Converter; import jota.utils.IotaAPIUtils; import okhttp3.OkHttpClient; import org.slf4j.Logger; @@ -15,10 +17,12 @@ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Properties; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * IotaAPIProxy Builder. Usage: @@ -193,10 +197,6 @@ public class IotaAPIProxy { // end of proxied calls. - public GetBundleResponse getBundle(String transaction) { - return IotaAPIUtils.getBundle(transaction); - } - /** * Generates a new address from a seed and returns the remainderAddress. * This is either done deterministically, or by providing the index of the new remainderAddress @@ -240,8 +240,72 @@ public class IotaAPIProxy { return GetNewAddressResponse.create(allAddresses); } + /* + * newAddress + * broadcastAndStore + * sendTrytes + * + getTransactionsObjects + findTransactionObjects + getLatestInclusion + getInputs + prepareTransfers + sendTransfer + replayBundle + broadcastBundle + getBundle + getTransfers + getAccountData + */ + /** + * + * @param trytes + * @return a StoreTransactionsResponse + */ + public StoreTransactionsResponse broadcastAndStore(final String ... trytes) { + + try { + broadcastTransactions(trytes); + } catch (Exception e) { + log.error("Impossible to broadcastAndStore, aborting.", e); + throw new IllegalStateException("BroadcastAndStore Illegal state Exception"); + } + return storeTransactions(trytes); + + } + + /** + * Facade method: Gets transactions to approve, attaches to Tangle, broadcasts and stores + * @param {array} trytes + * @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.getBranchTransactionToApprove(), 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()); + } + public GetBundleResponse getBundle(String transaction) { + return null; //IotaAPIUtils.getBundle(transaction); + } + + public static class Builder { String protocol, host, port; diff --git a/src/main/java/jota/error/ArgumentException.java b/src/main/java/jota/error/ArgumentException.java index 759b694..c3da421 100644 --- a/src/main/java/jota/error/ArgumentException.java +++ b/src/main/java/jota/error/ArgumentException.java @@ -4,7 +4,10 @@ package jota.error; * Created by Adrian on 09.12.2016. */ public class ArgumentException extends BaseException { + + private static final long serialVersionUID = -7850044681919575720L; + public ArgumentException() { - super("wrong arguments passed to function"); + super("Wrong arguments passed to function"); } } diff --git a/src/main/java/jota/error/BaseException.java b/src/main/java/jota/error/BaseException.java index b1eb210..2931408 100644 --- a/src/main/java/jota/error/BaseException.java +++ b/src/main/java/jota/error/BaseException.java @@ -1,31 +1,29 @@ package jota.error; -import org.apache.commons.lang3.StringUtils; - +import java.util.Arrays; import java.util.Collection; /** * Created by Adrian on 09.12.2016. */ public class BaseException extends Exception { + + private static final long serialVersionUID = 5617085097507773343L; + protected Collection messages; public BaseException(String msg) { super(msg); } - public BaseException(String msg, Exception cause) { super(msg, cause); } - public BaseException(Collection messages) { - super(); this.messages = messages; } - public BaseException(Collection messages, Exception cause) { super(cause); this.messages = messages; @@ -33,19 +31,6 @@ public class BaseException extends Exception { @Override public String getMessage() { - String msg; - - if (this.messages != null && !this.messages.isEmpty()) { - msg = "["; - - for (String message : this.messages) { - msg += message + ","; - } - - msg = StringUtils.removeEnd(msg, ",") + "]"; - - } else msg = super.getMessage(); - - return msg; + return Arrays.toString(messages.toArray()); } } diff --git a/src/main/java/jota/error/NotEnoughBalanceException.java b/src/main/java/jota/error/NotEnoughBalanceException.java index c7099d6..64c516c 100644 --- a/src/main/java/jota/error/NotEnoughBalanceException.java +++ b/src/main/java/jota/error/NotEnoughBalanceException.java @@ -4,7 +4,10 @@ package jota.error; * Created by Adrian on 09.12.2016. */ public class NotEnoughBalanceException extends BaseException { + + private static final long serialVersionUID = -3807270816402226476L; + public NotEnoughBalanceException() { - super("not enough balance dude"); + super("Not enough balance"); } } diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java new file mode 100644 index 0000000..675fbd7 --- /dev/null +++ b/src/main/java/jota/model/Bundle.java @@ -0,0 +1,162 @@ +package jota.model; + +import jota.pow.Curl; +import jota.utils.Constants; +import jota.utils.Converter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pinpong on 09.12.16. + */ +public class Bundle { + + private List transactions; + private int length; + + public static String EMPTY_HASH = "999999999999999999999999999999999999999999999999999999999999999999999999999999999"; + + + public Bundle() { + this(new ArrayList(), 0); + } + + public Bundle(List transactions, int length) { + this.transactions = transactions; + this.length = length; + } + + public List getTransactions() { + return transactions; + } + + public void setTransactions(List transactions) { + this.transactions = transactions; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public void addEntry(int signatureMessageLength, String slice, long value, String tag, long timestamp) { + for (int i = 0; i < signatureMessageLength; i++) { + //TODO + +/* var transactionObject = new Object(); + transactionObject.address = address; + transactionObject.value = i == 0 ? value : 0; + transactionObject.tag = tag; + transactionObject.timestamp = timestamp; + + this.bundle[this.bundle.length] = transactionObject; +*/ + } + } + + public void finalize() { + + Curl curl = new Curl(); + curl.reset(); + + for (int i = 0; i < this.getTransactions().size(); i++) { + + int[] valueTrits = Converter.trits(this.getTransactions().get(i).getValue()); + while (valueTrits.length < 81) { + valueTrits[valueTrits.length] = 0; + } + + int[] timestampTrits = Converter.trits(this.getTransactions().get(i).getTimestamp()); + while (timestampTrits.length < 27) { + timestampTrits[timestampTrits.length] = 0; + } + + int[] currentIndexTrits = Converter.trits(this.getTransactions().get(i).setCurrentIndex("" + i)); + while (currentIndexTrits.length < 27) { + currentIndexTrits[currentIndexTrits.length] = 0; + } + + int[] lastIndexTrits = Converter.trits(this.getTransactions().get(i).setLastIndex("" + (this.getTransactions().size() - 1))); + while (lastIndexTrits.length < 27) { + lastIndexTrits[lastIndexTrits.length] = 0; + } + 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); + } + + int[] hash = new int[90]; + curl.squeeze(hash, 0, hash.length); + String hashInTrytes = Converter.trytes(hash); + + for (int i = 0; i < this.getTransactions().size(); i++) { + this.getTransactions().get(i).setBundle(hashInTrytes); + } + } + + + public void addTrytes(List signatureFragments) { + String emptySignatureFragment = ""; + String emptyHash = EMPTY_HASH; + + for (int j = 0; emptySignatureFragment.length() < 2187; j++) { + emptySignatureFragment += '9'; + } + + for (int i = 0; i < this.getTransactions().size(); i++) { + + // Fill empty signatureMessageFragment + this.getTransactions().get(i).setSignatureFragments(signatureFragments.get(i) == null ? signatureFragments.get(i) : emptySignatureFragment); + // Fill empty trunkTransaction + this.getTransactions().get(i).setTrunkTransaction(emptyHash); + + // Fill empty branchTransaction + this.getTransactions().get(i).setBranchTransaction(emptyHash); + + // Fill empty nonce + this.getTransactions().get(i).setNonce(emptyHash); + } + } + + public int[] normalizedBundle(String bundleHash) { + int[] normalizedBundle = new int[33 * 27 + 27]; + + for (int i = 0; i < 3; i++) { + + long sum = 0; + for (int j = 0; j < 27; j++) { + + sum += (normalizedBundle[i * 27 + j] = Converter.value(Converter.trits("" + bundleHash.charAt(i * 27 + j)))); + } + + if (sum >= 0) { + while (sum-- > 0) { + for (int j = 0; j < 27; j++) { + if (normalizedBundle[i * 27 + j] > -13) { + normalizedBundle[i * 27 + j]--; + break; + } + } + } + } else { + + while (sum++ < 0) { + + for (int j = 0; j < 27; j++) { + + if (normalizedBundle[i * 27 + j] < 13) { + normalizedBundle[i * 27 + j]++; + break; + } + } + } + } + } + + return normalizedBundle; + } + +} diff --git a/src/main/java/jota/model/Input.java b/src/main/java/jota/model/Input.java new file mode 100644 index 0000000..16ce445 --- /dev/null +++ b/src/main/java/jota/model/Input.java @@ -0,0 +1,48 @@ +package jota.model; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * Created by Adrian on 09.12.2016. + */ +public class Input { + private String address; + private long balance; + private int keyIndex; + + public Input(String address, long balance, int keyIndex) { + this.address = address; + this.balance = balance; + this.keyIndex = keyIndex; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public long getBalance() { + return balance; + } + + public void setBalance(long balance) { + this.balance = balance; + } + + public int getKeyIndex() { + return keyIndex; + } + + public void setKeyIndex(int keyIndex) { + this.keyIndex = keyIndex; + } +} \ No newline at end of file diff --git a/src/main/java/jota/pow/Curl.java b/src/main/java/jota/pow/Curl.java index d72ed45..764a54a 100644 --- a/src/main/java/jota/pow/Curl.java +++ b/src/main/java/jota/pow/Curl.java @@ -15,15 +15,37 @@ public class Curl { private int[] state = new int[STATE_LENGTH]; - public void absorb(final int[] trits, int offset, int length) { + public Curl absorb(final int[] trits, int offset, int length) { do { System.arraycopy(trits, offset, state, 0, length < HASH_LENGTH ? length : HASH_LENGTH); transform(); offset += HASH_LENGTH; } while ((length -= HASH_LENGTH) > 0); + + return this; } + public Curl transform() { + + final int[] scratchpad = new int[STATE_LENGTH]; + int scratchpadIndex = 0; + for (int round = 0; round < NUMBER_OF_ROUNDS; round++) { + System.arraycopy(state, 0, scratchpad, 0, STATE_LENGTH); + for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) { + state[stateIndex] = TRUTH_TABLE[scratchpad[scratchpadIndex] + scratchpad[scratchpadIndex += (scratchpadIndex < 365 ? 364 : -365)] * 3 + 4]; + } + } + return this; + } + + public Curl reset() { + for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) { + state[stateIndex] = 0; + } + return this; + } + public int[] squeeze(final int[] trits, int offset, int length) { do { @@ -35,26 +57,10 @@ public class Curl { return state; } - public void transform() { - - final int[] scratchpad = new int[STATE_LENGTH]; - int scratchpadIndex = 0; - for (int round = 0; round < NUMBER_OF_ROUNDS; round++) { - System.arraycopy(state, 0, scratchpad, 0, STATE_LENGTH); - for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) { - state[stateIndex] = TRUTH_TABLE[scratchpad[scratchpadIndex] + scratchpad[scratchpadIndex += (scratchpadIndex < 365 ? 364 : -365)] * 3 + 4]; - } - } - } - - public void reset() { - for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) { - state[stateIndex] = 0; - } - } - public int[] getState() { return state; } - public void setState(int[] state) { this.state = state; } + public void setState(int[] state) { + this.state = state; + } } diff --git a/src/main/java/jota/utils/Constants.java b/src/main/java/jota/utils/Constants.java index 2b9d4a5..5f8f9a2 100644 --- a/src/main/java/jota/utils/Constants.java +++ b/src/main/java/jota/utils/Constants.java @@ -11,5 +11,4 @@ public class Constants { public static int ADDRESS_LENGTH_WITHOUT_CHECKSUM = 81; public static int ADDRESS_LENGTH_WITH_CHECKSUM = 90; - } diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 0a94107..90550e7 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -4,8 +4,15 @@ import jota.model.Transaction; import jota.pow.Curl; import java.util.Arrays; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Converter { + + private static final Logger log = LoggerFactory.getLogger(Converter.class); private static final int RADIX = 3; private static final int MAX_TRIT_VALUE = (RADIX - 1) / 2, MIN_TRIT_VALUE = -MAX_TRIT_VALUE; @@ -146,20 +153,26 @@ public class Converter { } } } - - public static Transaction transactionObject(String trytes) { - if (trytes == null) return null; - + + public static Transaction transactionObject(final String trytes) { + + if (StringUtils.isEmpty(trytes)) { + log.warn("Warning: empty trytes in input for transactionObject"); + return null; + } + // validity check for (int i = 2279; i < 2295; i++) { if (trytes.charAt(i) != '9') { + log.warn("Trytes {} does not seem a valid tryte", trytes); return null; } } + int[] transactionTrits = Converter.trits(trytes); int[] hash = new int[90]; - Curl curl = new Curl(); + final Curl curl = new Curl(); // we need a fluent Curl. // generate the correct transaction hash curl.reset(); @@ -183,4 +196,4 @@ public class Converter { return trx; } -} \ No newline at end of file +} diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 3da5c2d..ee759cd 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,10 +1,17 @@ package jota.utils; -import jota.dto.response.GetBundleResponse; -import org.apache.commons.lang3.NotImplementedException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jota.model.Bundle; +import jota.model.Input; +import jota.model.Transaction; + /** * Client Side computation service * @@ -36,8 +43,112 @@ public class IotaAPIUtils { return address; } - public static GetBundleResponse getBundle(final String transaction) { - throw new NotImplementedException("Not yet implemented"); + public static String transactionTrytes(Transaction trx) { + int[] valueTrits = Converter.trits(trx.getValue()); + while (valueTrits.length < 81) { + valueTrits[valueTrits.length] = 0; + } + + int[] timestampTrits = Converter.trits(trx.getTimestamp()); + while (timestampTrits.length < 27) { + timestampTrits[timestampTrits.length] = 0; + } + + int[] currentIndexTrits = Converter.trits(trx.getTimestamp()); + while (currentIndexTrits.length < 27) { + currentIndexTrits[currentIndexTrits.length] = 0; + } + + int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex()); + while (lastIndexTrits.length < 27) { + lastIndexTrits[lastIndexTrits.length] = 0; + } + + 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(String seed, List inputs, Bundle bundle, + List signatureFragments) { + bundle.finalize(); + bundle.addTrytes(signatureFragments); + + // SIGNING OF INPUTS + // + // Here we do the actual signing of the inputs + // Iterate over all bundle transactions, find the inputs + // Get the corresponding private key and calculate the signatureFragment + for (int i = 0; i < bundle.getTransactions().size(); i++) { + if (Long.parseLong(bundle.getTransactions().get(i).getValue()) < 0) { + String thisAddress = bundle.getTransactions().get(i).getAddress(); + + // Get the corresponding keyIndex of the address + int keyIndex = 0; + for (int k = 0; k < inputs.size(); k++) { + if (inputs.get(k).getAddress().equals(thisAddress)) { + keyIndex = inputs.get(k).getKeyIndex(); + break; + } + } + + String bundleHash = bundle.getTransactions().get(i).getBundle(); + + // Get corresponding private key of address + int[] key = Signing.key(Converter.trits(seed), keyIndex, 2); + + // First 6561 trits for the firstFragment + int[] firstFragment = Arrays.copyOfRange(key, 0, 6561); + + // Get the normalized bundle hash + int[] normalizedBundleHash = bundle.normalizedBundle(bundleHash); + + // First bundle fragment uses 27 trytes + int[] firstBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 0, 27); + + // Calculate the new signatureFragment with the first bundle fragment + int[] firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); + + // Convert signature to trytes and assign the new signatureFragment + bundle.getTransactions().get(i).setSignatureFragments(Converter.trytes(firstSignedFragment)); + + // Because the signature is > 2187 trytes, we need to + // find the second transaction to add the remainder of the signature + for (int j = 0; j < bundle.getTransactions().size(); j++) { + // Same address as well as value = 0 (as we already spent the input) + if (bundle.getTransactions().get(j).getAddress() == thisAddress && Long.parseLong(bundle.getTransactions().get(j).getValue()) == 0) { + // Use the second 6562 trits + int[] secondFragment = Arrays.copyOfRange(key, 6561, 6561 * 2); + + // The second 27 to 54 trytes of the bundle hash + int[] secondBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 27, 27 * 2); + + // Calculate the new signature + int[] secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); + + // Convert signature to trytes and assign it again to this bundle entry + bundle.getTransactions().get(j).setSignatureFragments(Converter.trytes(secondSignedFragment)); + } + } + } + } + + List bundleTrytes = new ArrayList<>(); + + // Convert all bundle entries into trytes + for (Transaction tx : bundle.getTransactions()) { + bundleTrytes.add(IotaAPIUtils.transactionTrytes(tx)); + } + Collections.reverse(bundleTrytes); + return bundleTrytes; } } diff --git a/src/main/java/jota/utils/IotaUnitConverter.java b/src/main/java/jota/utils/IotaUnitConverter.java index cdd4529..d25a39e 100644 --- a/src/main/java/jota/utils/IotaUnitConverter.java +++ b/src/main/java/jota/utils/IotaUnitConverter.java @@ -43,8 +43,9 @@ public class IotaUnitConverter { public static IotaUnits findOptimalIotaUnitToDisplay(long amount) { int length = String.valueOf(amount).length(); - if (amount < 0) // do not count "-" sign + if (amount < 0) {// do not count "-" sign length -= 1; + } IotaUnits units = IotaUnits.IOTA; diff --git a/src/main/java/jota/utils/IotaUnits.java b/src/main/java/jota/utils/IotaUnits.java index 28e52f3..779dde0 100644 --- a/src/main/java/jota/utils/IotaUnits.java +++ b/src/main/java/jota/utils/IotaUnits.java @@ -8,6 +8,7 @@ package jota.utils; * Table of IOTA units based off of the standard system of Units **/ public enum IotaUnits { + IOTA("i", 0), KILO_IOTA("Ki", 3), MEGA_IOTA("Mi", 6), diff --git a/src/main/java/jota/utils/SeedRandomGenerator.java b/src/main/java/jota/utils/SeedRandomGenerator.java index 8e702cb..fa8b58c 100644 --- a/src/main/java/jota/utils/SeedRandomGenerator.java +++ b/src/main/java/jota/utils/SeedRandomGenerator.java @@ -1,6 +1,6 @@ package jota.utils; -import java.util.Random; +import java.security.SecureRandom; /** * Created by pinpong on 13.12.16. @@ -10,7 +10,7 @@ public class SeedRandomGenerator { public static String generateNewSeed() { char[] chars = Constants.TRYTE_ALPHABET.toCharArray(); StringBuilder builder = new StringBuilder(); - Random random = new Random(); + SecureRandom random = new SecureRandom(); for (int i = 0; i < Constants.SEED_LENGTH_MAX; i++) { char c = chars[random.nextInt(chars.length)]; builder.append(c); diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index a5e2553..f04339f 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -34,7 +34,6 @@ public class Signing { while (length-- > 0) { for (int i = 0; i < 27; i++) { - curl.squeeze(buffer, offset, buffer.length); for (int j = 0; j < 243; j++) { key.add(buffer[j]); @@ -81,6 +80,31 @@ public class Signing { } return digests; } + + public static int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) { + + int[] signatureFragment = keyFragment; + int[] hash; + + Curl curl = new Curl(); + + for (int i = 0; i < 27; i++) { + + hash = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243); + + for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) { + curl.reset() + .absorb(hash, 0, hash.length) + .squeeze(hash, 0, hash.length); + } + + for (int j = 0; j < 243; j++) { + signatureFragment[i * 243 + j] = hash[j]; + } + } + + return signatureFragment; + } public static int[] address(int[] digests) { final Curl curl = new Curl(); diff --git a/src/main/java/jota/utils/TrytesConverter.java b/src/main/java/jota/utils/TrytesConverter.java index 5c5d843..ab9d02a 100644 --- a/src/main/java/jota/utils/TrytesConverter.java +++ b/src/main/java/jota/utils/TrytesConverter.java @@ -4,7 +4,7 @@ package jota.utils; * Created by pinpong on 01.12.16. */ public class TrytesConverter { - + /** * Conversion of ascii encoded bytes to trytes. * Input is a string (can be stringified JSON object), return value is Trytes @@ -19,7 +19,9 @@ public class TrytesConverter { * b. The second value is the remainder (decimal value - first value), divided by 27 * 3. The two values returned from Step 2. are then input as indices into the available values list ('9ABCDEFGHIJKLMNOPQRSTUVWXYZ') to get the correct tryte value *

- * EXAMPLES + * + * EXAMPLE + * * Lets say we want to convert the ASCII character "Z". * 1. 'Z' has a decimal value of 90. * 2. 90 can be represented as 9 + 3 * 27. To make it simpler: @@ -30,10 +32,11 @@ public class TrytesConverter { * b. The second tryte value is '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'[3] === "C" * Our tryte pair is "IC" *

- * RESULT: - * The ASCII char "Z" is represented as "IC" in trytes. + * + * @param inputString + * @return + * The ASCII char "Z" is represented as "IC" in trytes. */ - public static String toTrytes(String inputString) { StringBuilder trytes = new StringBuilder(); @@ -67,7 +70,6 @@ public class TrytesConverter { * Last character = } * Everything after that is 9's padding */ - public static String toString(String inputTrytes) { StringBuilder string = new StringBuilder(); @@ -81,7 +83,6 @@ public class TrytesConverter { int decimalValue = firstValue + secondValue * 27; String character = Character.toString((char) decimalValue); - string.append(character); } diff --git a/src/test/java/jota/SendMessageTest.java b/src/test/java/jota/SendMessageTest.java new file mode 100644 index 0000000..9a62c04 --- /dev/null +++ b/src/test/java/jota/SendMessageTest.java @@ -0,0 +1,12 @@ +package jota; + +import org.junit.Test; + +public class SendMessageTest { + + @Test + public void sendMessage() { + + } + +} diff --git a/src/test/java/jota/TrytesConverterTest.java b/src/test/java/jota/TrytesConverterTest.java index 7741cff..28b54a6 100644 --- a/src/test/java/jota/TrytesConverterTest.java +++ b/src/test/java/jota/TrytesConverterTest.java @@ -3,6 +3,9 @@ package jota; import jota.utils.TrytesConverter; import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.lang3.RandomStringUtils; /** * Created by pinpong on 01.12.16. @@ -17,5 +20,14 @@ public class TrytesConverterTest { public void shouldConvertTrytesToString() { assertEquals(TrytesConverter.toString("IC"), "Z"); } + + @Test + public void shouldConvertBackAndForth() { + String str = RandomStringUtils.randomAlphabetic(1000).toUpperCase(); + System.err.println(str); + String back = TrytesConverter.toString(TrytesConverter.toTrytes(str)); + + assertTrue(str.equals(back)); + } } diff --git a/teststore.txt b/teststore.txt new file mode 100644 index 0000000..833978f --- /dev/null +++ b/teststore.txt @@ -0,0 +1 @@ +curl http://localhost:14265 -X POST -H Content-Type: application/json -d {'command': 'storeTransactions', 'trytes': ['GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCCOYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZWIKIRH9GCOEVZFKNXEVCUCIIWZQCQEUVRZOCMEL9AMGXJNMLJCIA9UWGRPPHCEOPTSVPKPPPCMQXYBHMSODTWUOABPKWFFFQJHCBVYXLHEWPD9YUDFTGNCYAKQKVEZYRBQRBXIAUX9SVEDUKGMTWQIYXRGSWYRK9SRONVGTW9YGHSZRIXWGPCCUCDRMAXBPDFVHSRYWHGB9DQSQFQKSNICGPIPTRZINYRXQAFSWSEWIFRMSBMGTNYPRWFSOIIWWT9IDSELM9JUOOWFNCCSHUSMGNROBFJX9JQ9XT9PKEGQYQAWAFPRVRRVQPUQBHLSNTEFCDKBWRCDX9EYOBB9KPMTLNNQLADBDLZPRVBCKVCYQEOLARJYAGTBFR9QLPKZBOYWZQOVKCVYRGYI9ZEFIQRKYXLJBZJDBJDJVQZCGYQMROVHNDBLGNLQODPUXFNTADDVYNZJUVPGB9LVPJIYLAPBOEHPMRWUIAJXVQOEM9ROEYUOTNLXVVQEYRQWDTQGDLEYFIYNDPRAIXOZEBCS9P99AZTQQLKEILEVXMSHBIDHLXKUOMMNFKPYHONKEYDCHMUNTTNRYVMMEYHPGASPZXASKRUPWQSHDMU9VPS99ZZ9SJJYFUJFFMFORBYDILBXCAVJDPDFHTTTIYOVGLRDYRTKHXJORJVYRPTDH9ZCPZ9ZADXZFRSFPIQKWLBRNTWJHXTOAUOL9FVGTUMMPYGYICJDXMOESEVDJWLMCVTJLPIEKBE9JTHDQWV9MRMEWFLPWGJFLUXI9BXPSVWCMUWLZSEWHBDZKXOLYNOZAPOYLQVZAQMOHGTTQEUAOVKVRRGAHNGPUEKHFVPVCOYSJAWHZU9DRROHBETBAFTATVAUGOEGCAYUXACLSSHHVYDHMDGJP9AUCLWLNTFEVGQGHQXSKEMVOVSKQEEWHWZUDTYOBGCURRZSJZLFVQQAAYQO9TRLFFN9HTDQXBSPPJYXMNGLLBHOMNVXNOWEIDMJVCLLDFHBDONQJCJVLBLCSMDOUQCKKCQJMGTSTHBXPXAMLMSXRIPUBMBAWBFNLHLUJTRJLDERLZFUBUSMF999XNHLEEXEENQJNOFFPNPQ9PQICHSATPLZVMVIWLRTKYPIXNFGYWOJSQDAXGFHKZPFLPXQEHCYEAGTIWIJEZTAVLNUMAFWGGLXMBNUQTOFCNLJTCDMWVVZGVBSEBCPFSM99FLOIDTCLUGPSEDLOKZUAEVBLWNMODGZBWOVQT9DPFOTSKRABQAVOQ9RXWBMAKFYNDCZOJGTCIDMQSQQSODKDXTPFLNOKSIZEOY9HFUTLQRXQMEPGOXQGLLPNSXAUCYPGZMNWMQWSWCKAQYKXJTWINSGPPZG9HLDLEAWUWEVCTVRCBDFOXKUROXH9HXXAXVPEJFRSLOGRVGYZASTEBAQNXJJROCYRTDPYFUIQJVDHAKEG9YACV9HCPJUEUKOYFNWDXCCJBIFQKYOXGRDHVTHEQUMHO999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999RKWEEVD99A99999999A99999999NFDPEEZCWVYLKZGSLCQNOFUSENIXRHWWTZFBXMPSQHEDFWZULBZFEOMNLRNIDQKDNNIELAOXOVMYEI9PGTKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999999TKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999999999999999999999999999999999999999999999999999999999999999999999999999999999999999']} From bbe837975e31bb2eb1e3907318a4601f906e751b Mon Sep 17 00:00:00 2001 From: davassi Date: Mon, 19 Dec 2016 19:03:11 +0100 Subject: [PATCH 034/111] Implemented prepareTransfer and getInputs --- src/main/java/jota/IotaAPIProxy.java | 371 ++++++++++++++++-- .../GetBalancesAndFormatResponse.java | 34 ++ .../dto/response/GetNewAddressResponse.java | 2 +- src/main/java/jota/model/Transfer.java | 63 ++- src/main/java/jota/pow/Curl.java | 8 + src/main/java/jota/utils/InputValidator.java | 47 +++ src/main/java/jota/utils/IotaAPIUtils.java | 6 +- src/main/java/jota/utils/Signing.java | 118 ++++-- src/test/java/jota/IotaAPIProxyTest.java | 2 +- 9 files changed, 576 insertions(+), 75 deletions(-) create mode 100644 src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 8901c71..6bb6032 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -1,28 +1,60 @@ package jota; -import jota.dto.request.*; -import jota.dto.response.*; -import jota.model.Transaction; -import jota.utils.Converter; -import jota.utils.IotaAPIUtils; -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.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jota.dto.request.IotaAttachToTangleRequest; +import jota.dto.request.IotaBroadcastTransactionRequest; +import jota.dto.request.IotaCommandRequest; +import jota.dto.request.IotaFindTransactionsRequest; +import jota.dto.request.IotaGetBalancesRequest; +import jota.dto.request.IotaGetInclusionStateRequest; +import jota.dto.request.IotaGetTransactionsToApproveRequest; +import jota.dto.request.IotaGetTrytesRequest; +import jota.dto.request.IotaNeighborsRequest; +import jota.dto.request.IotaStoreTransactionsRequest; +import jota.dto.response.AddNeighborsResponse; +import jota.dto.response.BroadcastTransactionsResponse; +import jota.dto.response.FindTransactionResponse; +import jota.dto.response.GetAttachToTangleResponse; +import jota.dto.response.GetBalancesAndFormatResponse; +import jota.dto.response.GetBalancesResponse; +import jota.dto.response.GetBundleResponse; +import jota.dto.response.GetInclusionStateResponse; +import jota.dto.response.GetNeighborsResponse; +import jota.dto.response.GetNewAddressResponse; +import jota.dto.response.GetNodeInfoResponse; +import jota.dto.response.GetTipsResponse; +import jota.dto.response.GetTransactionsToApproveResponse; +import jota.dto.response.GetTrytesResponse; +import jota.dto.response.InterruptAttachingToTangleResponse; +import jota.dto.response.RemoveNeighborsResponse; +import jota.dto.response.StoreTransactionsResponse; +import jota.model.Bundle; +import jota.model.Input; +import jota.model.Transaction; +import jota.model.Transfer; +import jota.utils.Converter; +import jota.utils.InputValidator; +import jota.utils.IotaAPIUtils; +import okhttp3.OkHttpClient; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; /** * IotaAPIProxy Builder. Usage: @@ -174,6 +206,10 @@ 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[] {})); + } public InterruptAttachingToTangleResponse interruptAttachingToTangle() { final Call res = service.interruptAttachingToTangle(IotaCommandRequest.createInterruptAttachToTangleRequest()); @@ -244,18 +280,20 @@ public class IotaAPIProxy { * newAddress * broadcastAndStore * sendTrytes - * - getTransactionsObjects - findTransactionObjects - getLatestInclusion - getInputs - prepareTransfers - sendTransfer - replayBundle - broadcastBundle - getBundle - getTransfers - getAccountData + * prepareTransfers + * getInputs + + getTransfers + sendTransfer + getBundle + + getTransactionsObjects + findTransactionObjects + getLatestInclusion + + replayBundle + broadcastBundle + getAccountData */ /** @@ -272,7 +310,6 @@ public class IotaAPIProxy { throw new IllegalStateException("BroadcastAndStore Illegal state Exception"); } return storeTransactions(trytes); - } /** @@ -296,16 +333,288 @@ public class IotaAPIProxy { throw new IllegalStateException("sendTrytes Illegal state Exception"); } - return Arrays.stream(res.getTrytes()) - .map(Converter::transactionObject) - .collect(Collectors.toList()); + //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)); + } + return trx; + } + + public List findAndGetTxs(final String addresses) { + + final FindTransactionResponse res = findTransactionsByAddresses(addresses); + return getTransactionsObjects(res.getHashes()); + } + + /** + * 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 + **/ + public List getTransactionsObjects(String ... hashes) { + + if (!InputValidator.isArrayOfHashes(hashes)) { + throw new IllegalStateException("Not an Array of Hashes: " + Arrays.toString(hashes)); + } + + final GetTrytesResponse trytesResponse = getTrytes(hashes); + + final List trxs = new ArrayList<>(); + + for (final String tryte : trytesResponse.getTrytes()) { + trxs.add(Converter.transactionObject(tryte)); + } + return trxs; } + /** + * 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 + **/ + public List prepareTransfers(final String seed, final List transfers, String remainder, List inputs) { + + // Input validation of transfers object + if (!InputValidator.isTransfersCollectionCorrect(transfers)) { + throw new IllegalStateException("Invalid Transfer"); + } + + // Create a new bundle + final Bundle bundle = new Bundle(); + final List signatureFragments = new ArrayList<>(); + + int totalValue = 0; + String tag; + + // Iterate over all transfers, get totalValue + // and prepare the signatureFragments, message and tag + for (final Transfer transfer : transfers) { + + int signatureMessageLength = 1; + + // If message longer than 2187 trytes, increase signatureMessageLength (add 2nd transaction) + if (transfer.getMessage().length() > 2187) { + + // Get total length, message / maxLength (2187 trytes) + signatureMessageLength += Math.floor(transfer.getMessage().length() / 2187); + + String msgCopy = new String(transfer.getMessage()); + + // 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()); + + // Pad remainder of fragment + for (int j = 0; fragment.length() < 2187; j++) { + fragment += "9"; + } + + signatureFragments.add(fragment); + } + } else { + // Else, get single fragment with 2187 of 9's trytes + String fragment = StringUtils.substring(transfer.getMessage(), 0, 2187); + + for (int j = 0; fragment.length() < 2187; j++) { + fragment += '9'; + } + + signatureFragments.add(fragment); + } + + // get current timestamp in seconds + long timestamp = (long) Math.floor(Calendar.getInstance().getTimeInMillis() / 1000); + + // If no tag defined, get 27 tryte tag. + tag = transfer.getTag().isEmpty() ? "999999999999999999999999999" : transfer.getTag(); + + // Pad for required 27 tryte length + for (int j = 0; tag.length() < 27; j++) { + tag += '9'; + } + + // Add first entry to the bundle + bundle.addEntry(signatureMessageLength, transfer.getAddress(), transfer.getValue(), tag, timestamp); + // Sum up total value + totalValue += transfer.getValue(); + } + + // Get inputs if we are sending tokens + if (totalValue != 0) { + + // Case 1: user provided inputs + // Validate the inputs by calling getBalances + if (!inputs.isEmpty()) { + + // Get list if addresses of the provided inputs + List inputsAddresses = new ArrayList<>(); + for (final Input i : inputs) { + inputsAddresses.add(i.getAddress()); + } + + GetBalancesResponse resbalances = getBalances(100, inputsAddresses); + String[] balances = resbalances.getBalances(); + + + List confirmedInputs = new ArrayList<>(); + int totalBalance = 0; int i = 0; + for (String balance : balances) { + long thisBalance = Integer.parseInt(balance); + totalBalance += thisBalance; + + // If input has balance, add it to confirmedInputs + if (thisBalance > 0) { + Input inputEl = inputs.get(i++); + inputEl.setBalance(thisBalance); + confirmedInputs.add(inputEl); + } + } + + // Return not enough balance error + if (totalValue > totalBalance) { + throw new IllegalStateException("Not enough balance"); + } + + return IotaAPIUtils.signInputsAndReturn(seed, confirmedInputs, bundle, signatureFragments); + } + + // Case 2: Get inputs deterministically + // + // If no inputs provided, derive the addresses from the seed and + // confirm that the inputs exceed the threshold + else { + + GetBalancesAndFormatResponse newinputs = getInputs(seed, Collections.EMPTY_LIST, 0, 0, totalValue); + // If inputs with enough balance + return IotaAPIUtils.signInputsAndReturn(seed, newinputs.getInput(), bundle, signatureFragments); + } + } else { + + // If no input required, don't sign and simply finalize the bundle + bundle.finalize(); + bundle.addTrytes(signatureFragments); + + List trxb = bundle.getTransactions(); + List bundleTrytes = new ArrayList<>(); + for (Transaction tx : trxb) { + jota.utils.IotaAPIUtils.transactionTrytes(tx); + } + Collections.reverse(bundleTrytes); + 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 + **/ + public GetBalancesAndFormatResponse getInputs(final String seed, final List balances, int start, int end, int threshold) { + + // validate the seed + if (!InputValidator.isTrytes(seed, 0)) { + throw new IllegalStateException("Invalid Seed"); + } + + // If start value bigger than end, return error + // or if difference between end and start is bigger than 500 keys + if (start > end || end > (start + 500)) { + throw new IllegalStateException("Invalid inputs provided"); + } + + // Case 1: start and end + // + // If start and end is defined by the user, simply iterate through the keys + // and call getBalances + if (end != 0) { + + List allAddresses = new ArrayList<>(); + + for (int i = start; i < end; i++) { + + String address = IotaAPIUtils.newAddress(seed, i, false); + allAddresses.add(address); + } + + return getBalanceAndFormat(allAddresses, balances, threshold, start, end); + } + // Case 2: iterate till threshold || end + // + // Either start from index: 0 or start (if defined) until threshold is reached. + // 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); + } + } + + // Calls getBalances and formats the output + // returns the final inputsObject then + public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, + final List balances, long threshold, int start, int end) { + + GetBalancesResponse bres = getBalances(100, addresses); + + // If threshold defined, keep track of whether reached or not + // else set default to true + 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); + + inputs.add(newEntry); + // Increase totalBalance of all aggregated inputs + totalBalance += balance; + + if (thresholdReached == false && totalBalance >= threshold) { + thresholdReached = true; + break; + } + } + } + + if (thresholdReached) { + return GetBalancesAndFormatResponse.create(inputs, totalBalance); + } + throw new IllegalStateException("Not enough balance"); + } + public GetBundleResponse getBundle(String transaction) { return null; //IotaAPIUtils.getBundle(transaction); } - public static class Builder { String protocol, host, port; diff --git a/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java b/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java new file mode 100644 index 0000000..493d063 --- /dev/null +++ b/src/main/java/jota/dto/response/GetBalancesAndFormatResponse.java @@ -0,0 +1,34 @@ +package jota.dto.response; + +import java.util.List; + +import jota.model.Input; + +public class GetBalancesAndFormatResponse extends AbstractResponse { + + private List input; + private long totalBalance; + + public List getInput() { + return input; + } + + 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) { + GetBalancesAndFormatResponse res = new GetBalancesAndFormatResponse(); + res.setInput(inputs); + res.setTotalBalance(totalBalance2); + return res; + } +} diff --git a/src/main/java/jota/dto/response/GetNewAddressResponse.java b/src/main/java/jota/dto/response/GetNewAddressResponse.java index b54384d..484e17e 100644 --- a/src/main/java/jota/dto/response/GetNewAddressResponse.java +++ b/src/main/java/jota/dto/response/GetNewAddressResponse.java @@ -12,7 +12,7 @@ public class GetNewAddressResponse extends AbstractResponse { return res; } - public List getAddress() { + public List getAddresses() { return addresses; } } diff --git a/src/main/java/jota/model/Transfer.java b/src/main/java/jota/model/Transfer.java index fa149ee..a1b675e 100644 --- a/src/main/java/jota/model/Transfer.java +++ b/src/main/java/jota/model/Transfer.java @@ -1,7 +1,6 @@ package jota.model; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; +import com.google.gson.Gson; /** * Created by pinpong on 02.12.16. @@ -11,21 +10,33 @@ public class Transfer { private String timestamp; private String address; private String hash; - private Integer persistence; + private Boolean persistence; private long value; + private String message; + private String tag; - public Transfer(String timestamp, String address, String hash, Integer persistence, long value) { - + public Transfer(String timestamp, String address, String hash, Boolean persistence, long value, String message, + String tag) { this.timestamp = timestamp; this.address = address; this.hash = hash; this.persistence = persistence; this.value = value; + this.message = message; + this.tag = tag; + + } + + public Transfer(String address, long value, String message, String tag) { + this.address = address; + this.value = value; + this.message = message; + this.tag = tag; } @Override public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + return new Gson().toJson(this); } public String getAddress() { @@ -36,7 +47,7 @@ public class Transfer { return hash; } - public Integer getPersistence() { + public Boolean getPersistence() { return persistence; } @@ -47,4 +58,40 @@ public class Transfer { public long getValue() { return value; } -} + + public String getMessage() { + return message; + } + + public String getTag() { + return tag; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public void setAddress(String address) { + this.address = address; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public void setPersistence(Boolean persistence) { + this.persistence = persistence; + } + + public void setValue(long value) { + this.value = value; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setTag(String tag) { + this.tag = tag; + } +} \ No newline at end of file diff --git a/src/main/java/jota/pow/Curl.java b/src/main/java/jota/pow/Curl.java index 764a54a..b804250 100644 --- a/src/main/java/jota/pow/Curl.java +++ b/src/main/java/jota/pow/Curl.java @@ -25,6 +25,10 @@ public class Curl { return this; } + + public Curl absorb(final int[] trits) { + return absorb(trits, 0, trits.length); + } public Curl transform() { @@ -56,6 +60,10 @@ public class Curl { return state; } + + public int[] squeeze(final int[] trits) { + return squeeze(trits, 0, trits.length); + } public int[] getState() { return state; diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index d658bd3..6e85443 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -1,5 +1,12 @@ package jota.utils; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; + +import jota.model.Transaction; +import jota.model.Transfer; + /** * Created by pinpong on 02.12.16. */ @@ -20,6 +27,10 @@ public class InputValidator { public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } + + public static boolean isValue(final String value) { + return StringUtils.isNumeric(value); + } public static boolean isArrayOfHashes(String[] hashes) { if (hashes == null) return false; @@ -38,4 +49,40 @@ public class InputValidator { } return true; } + + /** + * checks if input is correct hash collections + * + * @method isTransfersArray + * @param {array} hash + * @returns {boolean} + **/ + public static boolean isTransfersCollectionCorrect(final List transfers) { + + for (final Transfer transfer : transfers) { + if (!isTransfersArray(transfer)) { + return false; + } + } + return true; + } + + public static boolean isTransfersArray(final Transfer transfer) { + + if (!isAddress(transfer.getAddress())) { + return false; + } + + // Check if message is correct trytes of any length + if (!isTrytes(transfer.getMessage(), 0)) { + return false; + } + + // Check if tag is correct trytes of {0,27} trytes + if (!isTrytes(transfer.getTag(), 27)) { + return false; + } + + return true; + } } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index ee759cd..617f014 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -77,8 +77,10 @@ public class IotaAPIUtils { + trx.getNonce(); } - public static List signInputsAndReturn(String seed, List inputs, Bundle bundle, - List signatureFragments) { + public static List signInputsAndReturn(final String seed, + final List inputs, + final Bundle bundle, + final List signatureFragments) { bundle.finalize(); bundle.addTrytes(signatureFragments); diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index f04339f..e0f2e84 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import jota.model.Bundle; import jota.pow.Curl; public class Signing { @@ -52,35 +53,6 @@ public class Signing { return a; } - public static int[] digests(int[] key) { - final Curl curl = new Curl(); - - int[] digests = new int[(int) Math.floor(key.length / 6561) * 243]; - int[] buffer = new int[243]; - - for (int i = 0; i < Math.floor(key.length / 6561); i++) { - int[] keyFragment = Arrays.copyOfRange(key, i * 6561, (i + 1) * 6561); - - for (int j = 0; j < 27; j++) { - - buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); - for (int k = 0; k < 26; k++) { - curl.reset(); - curl.absorb(buffer, 0, buffer.length); - curl.squeeze(buffer, 0, buffer.length); - } - System.arraycopy(buffer, 0, keyFragment, j * 243, 243); - } - - curl.reset(); - curl.absorb(keyFragment, 0, keyFragment.length); - curl.squeeze(buffer, 0, buffer.length); - - System.arraycopy(buffer, 0, digests, i * 243, 243); - } - return digests; - } - public static int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) { int[] signatureFragment = keyFragment; @@ -109,9 +81,91 @@ public class Signing { public static int[] address(int[] digests) { final Curl curl = new Curl(); int[] address = new int[243]; - curl.reset(); - curl.absorb(digests, 0, digests.length); - curl.squeeze(address, 0, address.length); + curl.reset() + .absorb(digests) + .squeeze(address); return address; } + + public static int[] digests(int[] key) { + final Curl curl = new Curl(); + + int[] digests = new int[(int) Math.floor(key.length / 6561) * 243]; + int[] buffer = new int[243]; + + for (int i = 0; i < Math.floor(key.length / 6561); i++) { + int[] keyFragment = Arrays.copyOfRange(key, i * 6561, (i + 1) * 6561); + + for (int j = 0; j < 27; j++) { + + buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); + for (int k = 0; k < 26; k++) { + curl.reset() + .absorb(buffer) + .squeeze(buffer); + } + System.arraycopy(buffer, 0, keyFragment, j * 243, 243); + } + + curl.reset(); + curl.absorb(keyFragment, 0, keyFragment.length); + curl.squeeze(buffer, 0, buffer.length); + + System.arraycopy(buffer, 0, digests, i * 243, 243); + } + return digests; + } + + public static int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) { + + int[] buffer = new int[243]; + + Curl curl = new Curl().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; ) { + + new Curl().reset() + .absorb(buffer) + .squeeze(buffer); + } + curl.absorb(buffer); + } + curl.squeeze(buffer); + + return buffer; + } + + public static Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) { + + Bundle bundle = new Bundle(); + + int[][] normalizedBundleFragments = new int[3][27]; + int[] normalizedBundleHash = bundle.normalizedBundle(bundleHash); + + // Split hash into 3 fragments + for (int i = 0; i < 3; i++) { + normalizedBundleFragments[i] = Arrays.copyOfRange(normalizedBundleHash, i * 27, (i + 1) * 27); + } + + // Get digests + int[] digests = new int[signatureFragments.length * 243 + 243]; + + for (int i = 0; i < signatureFragments.length; i++) { + + int[] digestBuffer = digest(normalizedBundleFragments[i % 3], Converter.trits(signatureFragments[i])); + + for (int j = 0; j < 243; j++) { + + digests[i * 243 + j] = digestBuffer[j]; + } + } + + String address = Converter.trytes(address(digests)); + + return (expectedAddress.equals(address)); + } } + diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 9b16cda..7f62a73 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -129,6 +129,6 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); - assertThat(res.getAddress(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); + assertThat(res.getAddresses(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); } } \ No newline at end of file From bee2aa330260b193e19cb6efc2f63069ca259f0d Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Thu, 22 Dec 2016 10:19:21 +0100 Subject: [PATCH 035/111] fixed getTransactionsToApprove (#12) * updated GetNodeInfo * fixed getTransactionsToApprove * fixed getTransactionsToApprove --- src/main/java/jota/IotaAPIProxy.java | 2 +- .../java/jota/dto/response/GetNodeInfoResponse.java | 5 +++++ .../response/GetTransactionsToApproveResponse.java | 12 ++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 6bb6032..7ec6373 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -324,7 +324,7 @@ public class IotaAPIProxy { final GetTransactionsToApproveResponse txs = getTransactionsToApprove(minWeightMagnitude); // attach to tangle - do pow - final GetAttachToTangleResponse res = attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransactionToApprove(), minWeightMagnitude, trytes); + final GetAttachToTangleResponse res = attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); try { broadcastAndStore(res.getTrytes()); diff --git a/src/main/java/jota/dto/response/GetNodeInfoResponse.java b/src/main/java/jota/dto/response/GetNodeInfoResponse.java index f7477e4..233c0fb 100644 --- a/src/main/java/jota/dto/response/GetNodeInfoResponse.java +++ b/src/main/java/jota/dto/response/GetNodeInfoResponse.java @@ -4,6 +4,7 @@ public class GetNodeInfoResponse extends AbstractResponse { private String appName; private String appVersion; + private String jreVersion; private int jreAvailableProcessors; private long jreFreeMemory; private long jreMaxMemory; @@ -26,6 +27,10 @@ public class GetNodeInfoResponse extends AbstractResponse { return appVersion; } + public String getJreVersion() { + return jreVersion; + } + public Integer getJreAvailableProcessors() { return jreAvailableProcessors; } diff --git a/src/main/java/jota/dto/response/GetTransactionsToApproveResponse.java b/src/main/java/jota/dto/response/GetTransactionsToApproveResponse.java index 5f76cf3..ba7d478 100644 --- a/src/main/java/jota/dto/response/GetTransactionsToApproveResponse.java +++ b/src/main/java/jota/dto/response/GetTransactionsToApproveResponse.java @@ -3,13 +3,13 @@ package jota.dto.response; public class GetTransactionsToApproveResponse extends AbstractResponse { private String trunkTransaction; - private String branchTransactionToApprove; - - public String getBranchTransactionToApprove() { - return branchTransactionToApprove; - } + private String branchTransaction; public String getTrunkTransaction() { return trunkTransaction; } -} + + public String getBranchTransaction() { + return branchTransaction; + } +} \ No newline at end of file From 9af3d2d0277059e8dc29b63888220a39eb2e7b4e Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Thu, 22 Dec 2016 14:55:13 +0100 Subject: [PATCH 036/111] updated tests (#13) * updated tests * Bundle: fixed addEntry --- src/main/java/jota/IotaAPIProxy.java | 58 +++++------------------ src/main/java/jota/model/Bundle.java | 16 +++---- src/main/java/jota/model/Transaction.java | 8 ++++ src/test/java/jota/IotaAPIProxyTest.java | 54 +++++++++++++++++---- 4 files changed, 73 insertions(+), 63 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 7ec6373..1f9de61 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -1,48 +1,7 @@ package jota; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import jota.dto.request.IotaAttachToTangleRequest; -import jota.dto.request.IotaBroadcastTransactionRequest; -import jota.dto.request.IotaCommandRequest; -import jota.dto.request.IotaFindTransactionsRequest; -import jota.dto.request.IotaGetBalancesRequest; -import jota.dto.request.IotaGetInclusionStateRequest; -import jota.dto.request.IotaGetTransactionsToApproveRequest; -import jota.dto.request.IotaGetTrytesRequest; -import jota.dto.request.IotaNeighborsRequest; -import jota.dto.request.IotaStoreTransactionsRequest; -import jota.dto.response.AddNeighborsResponse; -import jota.dto.response.BroadcastTransactionsResponse; -import jota.dto.response.FindTransactionResponse; -import jota.dto.response.GetAttachToTangleResponse; -import jota.dto.response.GetBalancesAndFormatResponse; -import jota.dto.response.GetBalancesResponse; -import jota.dto.response.GetBundleResponse; -import jota.dto.response.GetInclusionStateResponse; -import jota.dto.response.GetNeighborsResponse; -import jota.dto.response.GetNewAddressResponse; -import jota.dto.response.GetNodeInfoResponse; -import jota.dto.response.GetTipsResponse; -import jota.dto.response.GetTransactionsToApproveResponse; -import jota.dto.response.GetTrytesResponse; -import jota.dto.response.InterruptAttachingToTangleResponse; -import jota.dto.response.RemoveNeighborsResponse; -import jota.dto.response.StoreTransactionsResponse; +import jota.dto.request.*; +import jota.dto.response.*; import jota.model.Bundle; import jota.model.Input; import jota.model.Transaction; @@ -51,11 +10,20 @@ import jota.utils.Converter; import jota.utils.InputValidator; import jota.utils.IotaAPIUtils; import okhttp3.OkHttpClient; +import org.apache.commons.lang3.StringUtils; +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: * @@ -413,7 +381,7 @@ public class IotaAPIProxy { // Get total length, message / maxLength (2187 trytes) signatureMessageLength += Math.floor(transfer.getMessage().length() / 2187); - String msgCopy = new String(transfer.getMessage()); + String msgCopy = transfer.getMessage(); // While there is still a message, copy it while (!msgCopy.isEmpty()) { @@ -598,7 +566,7 @@ public class IotaAPIProxy { // Increase totalBalance of all aggregated inputs totalBalance += balance; - if (thresholdReached == false && totalBalance >= threshold) { + if (!thresholdReached && totalBalance >= threshold) { thresholdReached = true; break; } diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 675fbd7..90d966d 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -1,7 +1,6 @@ package jota.model; import jota.pow.Curl; -import jota.utils.Constants; import jota.utils.Converter; import java.util.ArrayList; @@ -43,18 +42,14 @@ public class Bundle { this.length = length; } - public void addEntry(int signatureMessageLength, String slice, long value, String tag, long timestamp) { + public void addEntry(int signatureMessageLength, String address, long value, String tag, long timestamp) { for (int i = 0; i < signatureMessageLength; i++) { - //TODO -/* var transactionObject = new Object(); - transactionObject.address = address; - transactionObject.value = i == 0 ? value : 0; - transactionObject.tag = tag; - transactionObject.timestamp = timestamp; + List transactions = new ArrayList<>(getTransactions()); + transactions.add(new Transaction(address, String.valueOf(i == 0 ? value : 0), tag, String.valueOf(timestamp))); + + setTransactions(transactions); - this.bundle[this.bundle.length] = transactionObject; -*/ } } @@ -84,6 +79,7 @@ public class Bundle { while (lastIndexTrits.length < 27) { lastIndexTrits[lastIndexTrits.length] = 0; } + 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); } diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 8a74f5a..0f7f962 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -41,6 +41,14 @@ public class Transaction { this.nonce = nonce; } + + public Transaction(String address, String value, String tag, String timestamp) { + this.address = address; + this.value = value; + this.tag = tag; + this.timestamp = timestamp; + } + @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 7f62a73..43b4c94 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,12 +3,15 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; +import jota.model.Transfer; import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; 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; @@ -28,6 +31,9 @@ public class IotaAPIProxyTest { 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 IotaAPIProxy proxy; @@ -40,6 +46,21 @@ public class IotaAPIProxyTest { 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()); } @Test @@ -70,25 +91,25 @@ public class IotaAPIProxyTest { public void shouldFindTransactionsByAddresses() { FindTransactionResponse trans = proxy.findTransactionsByAddresses(TEST_ADDRESS_WITH_CHECKSUM); System.err.println(gson.toJson(trans)); - assertThat(trans, IsNull.notNullValue()); + assertThat(trans.getHashes(), IsNull.notNullValue()); } @Test public void shouldFindTransactionsByApprovees() { FindTransactionResponse trans = proxy.findTransactionsByApprovees(new String[]{TEST_HASH}); - assertThat(trans, IsNull.notNullValue()); + assertThat(trans.getHashes(), IsNull.notNullValue()); } @Test public void shouldFindTransactionsByBundles() { FindTransactionResponse trans = proxy.findTransactionsByBundles(TEST_HASH); - assertThat(trans, IsNull.notNullValue()); + assertThat(trans.getHashes(), IsNull.notNullValue()); } @Test public void shouldFindTransactionsByDigests() { FindTransactionResponse trans = proxy.findTransactionsByDigests(TEST_HASH); - assertThat(trans, IsNull.notNullValue()); + assertThat(trans.getHashes(), IsNull.notNullValue()); } @@ -97,27 +118,32 @@ public class IotaAPIProxyTest { @Test public void shouldGetTrytes() { GetTrytesResponse res = proxy.getTrytes(TEST_HASH); - assertThat(res, IsNull.notNullValue()); + assertThat(res.getTrytes(), IsNull.notNullValue()); } @Test public void shouldGetInclusionStates() { GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); - assertThat(res, IsNull.notNullValue()); + assertThat(res.getStates(), IsNull.notNullValue()); } @Test // very long execution public void shouldGetTransactionsToApprove() { GetTransactionsToApproveResponse res = proxy.getTransactionsToApprove(27); - assertThat(res, IsNull.notNullValue()); + assertThat(res.getTrunkTransaction(), IsNull.notNullValue()); + assertThat(res.getBranchTransaction(), IsNull.notNullValue()); + } @Test public void shouldGetBalances() { GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); System.err.println(res); - assertThat(res, IsNull.notNullValue()); + assertThat(res.getBalances(), IsNull.notNullValue()); + assertThat(res.getMilestone(), IsNull.notNullValue()); + assertThat(res.getMilestoneIndex(), IsNull.notNullValue()); + } @Test @@ -131,4 +157,16 @@ public class IotaAPIProxyTest { final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); assertThat(res.getAddresses(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); } + + @Test + public void shouldPrepareTransfer() { + List transfers = new ArrayList<>(); + transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITH_CHECKSUM, 0, TEST_MESSAGE, TEST_TAG)); + proxy.prepareTransfers(TEST_SEED, transfers, null, null); + } + + @Test + public void shouldSendTrytes() { + proxy.sendTrytes(TEST_TRYTES, 18); + } } \ No newline at end of file From 96fed0bf788298db7e1d228b2451df6289a5747e Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 22 Dec 2016 15:57:20 +0100 Subject: [PATCH 037/111] added getLatestInclusion --- src/main/java/jota/IotaAPIProxy.java | 18 ++++++++++++++---- src/test/java/jota/IotaAPIProxyTest.java | 6 ++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 1f9de61..0f8010f 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -250,15 +250,15 @@ public class IotaAPIProxy { * sendTrytes * prepareTransfers * getInputs - + * getLatestInclusion + getTransfers sendTransfer getBundle getTransactionsObjects findTransactionObjects - getLatestInclusion - + replayBundle broadcastBundle getAccountData @@ -582,7 +582,17 @@ public class IotaAPIProxy { public GetBundleResponse getBundle(String transaction) { return null; //IotaAPIUtils.getBundle(transaction); } - + + + public GetInclusionStateResponse getLatestInclusion(String[] hashes) { + GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); + if (getNodeInfoResponse == null) return null; + + String[] latestMilestone = {getNodeInfoResponse.getLatestSolidSubtangleMilestone()}; + + return getInclusionStates(hashes, latestMilestone); + } + public static class Builder { String protocol, host, port; diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 43b4c94..bdea1b1 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -169,4 +169,10 @@ public class IotaAPIProxyTest { public void shouldSendTrytes() { proxy.sendTrytes(TEST_TRYTES, 18); } + + @Test + public void shouldGetLastInclusionState() { + GetInclusionStateResponse res = proxy.getLatestInclusion(new String[]{TEST_HASH}); + assertThat(res.getStates(), IsNull.notNullValue()); + } } \ No newline at end of file From 6a7a015ec65487d2e48d5f39091a17e294368720 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 22 Dec 2016 18:47:41 +0100 Subject: [PATCH 038/111] added findTransactionObjects --- src/main/java/jota/IotaAPIProxy.java | 18 +++++++++++------- src/test/java/jota/IotaAPIProxyTest.java | 5 +++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 0f8010f..d920943 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -309,13 +309,7 @@ public class IotaAPIProxy { } return trx; } - - public List findAndGetTxs(final String addresses) { - final FindTransactionResponse res = findTransactionsByAddresses(addresses); - return getTransactionsObjects(res.getHashes()); - } - /** * Wrapper function for getTrytes and transactionObjects * gets the trytes and transaction object from a list of transaction hashes @@ -326,7 +320,7 @@ public class IotaAPIProxy { * @returns {function} callback * @returns {object} success **/ - public List getTransactionsObjects(String ... hashes) { + public List getTransactionsObjects(String[] hashes) { if (!InputValidator.isArrayOfHashes(hashes)) { throw new IllegalStateException("Not an Array of Hashes: " + Arrays.toString(hashes)); @@ -342,6 +336,16 @@ public class IotaAPIProxy { return trxs; } + public List findTransactionObjects(String[] input) { + FindTransactionResponse ftr = findTransactions(input, null, null, null); + if (ftr == null || ftr.getHashes() == null) + + return null; + + // get the transaction objects of the transactions + return getTransactionsObjects(ftr.getHashes()); + } + /** * Prepares transfer by generating bundle, finding and signing inputs * diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index bdea1b1..ffb52ac 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -175,4 +175,9 @@ public class IotaAPIProxyTest { GetInclusionStateResponse res = proxy.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()); + } } \ No newline at end of file From 9dfa0e315c54897586af8e4c82a491f1c3839372 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 22 Dec 2016 19:34:31 +0100 Subject: [PATCH 039/111] added documentation --- src/main/java/jota/IotaAPIProxy.java | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index d920943..7946d67 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -336,6 +336,16 @@ public class IotaAPIProxy { return trxs; } + /** + * Wrapper function for findTransactions, getTrytes and transactionObjects + * Returns the transactionObject of a transaction hash. The input can be a valid + * findTransactions input + * + * @param {object} input + * @method getTransactionsObjects + * @returns {function} callback + * @returns {object} success + **/ public List findTransactionObjects(String[] input) { FindTransactionResponse ftr = findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) @@ -582,12 +592,27 @@ public class IotaAPIProxy { } 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 + * + * @method getBundle + * @param {string} transaction Hash of a tail transaction + * @returns {list} bundle Transaction objects + **/ public GetBundleResponse getBundle(String transaction) { return null; //IotaAPIUtils.getBundle(transaction); } - + /** + * Wrapper function for getNodeInfo and getInclusionStates + * + * @method getLatestInclusion + * @param {array} hashes + * @returns {function} callback + * @returns {array} state + **/ public GetInclusionStateResponse getLatestInclusion(String[] hashes) { GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); if (getNodeInfoResponse == null) return null; From 3a3f7f6a596e85ef373ebd1af0fb78c1b63468b7 Mon Sep 17 00:00:00 2001 From: Oliver Nitzschke Date: Fri, 23 Dec 2016 09:48:15 +0100 Subject: [PATCH 040/111] added getLatestInclusion (#14) * added getLatestInclusion * added findTransactionObjects * added documentation --- src/main/java/jota/IotaAPIProxy.java | 63 +++++++++++++++++++----- src/test/java/jota/IotaAPIProxyTest.java | 11 +++++ 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 1f9de61..7946d67 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -250,15 +250,15 @@ public class IotaAPIProxy { * sendTrytes * prepareTransfers * getInputs - + * getLatestInclusion + getTransfers sendTransfer getBundle getTransactionsObjects findTransactionObjects - getLatestInclusion - + replayBundle broadcastBundle getAccountData @@ -309,13 +309,7 @@ public class IotaAPIProxy { } return trx; } - - public List findAndGetTxs(final String addresses) { - final FindTransactionResponse res = findTransactionsByAddresses(addresses); - return getTransactionsObjects(res.getHashes()); - } - /** * Wrapper function for getTrytes and transactionObjects * gets the trytes and transaction object from a list of transaction hashes @@ -326,7 +320,7 @@ public class IotaAPIProxy { * @returns {function} callback * @returns {object} success **/ - public List getTransactionsObjects(String ... hashes) { + public List getTransactionsObjects(String[] hashes) { if (!InputValidator.isArrayOfHashes(hashes)) { throw new IllegalStateException("Not an Array of Hashes: " + Arrays.toString(hashes)); @@ -342,6 +336,26 @@ public class IotaAPIProxy { return trxs; } + /** + * Wrapper function for findTransactions, getTrytes and transactionObjects + * Returns the transactionObject of a transaction hash. The input can be a valid + * findTransactions input + * + * @param {object} input + * @method getTransactionsObjects + * @returns {function} callback + * @returns {object} success + **/ + public List findTransactionObjects(String[] input) { + FindTransactionResponse ftr = findTransactions(input, null, null, null); + if (ftr == null || ftr.getHashes() == null) + + return null; + + // get the transaction objects of the transactions + return getTransactionsObjects(ftr.getHashes()); + } + /** * Prepares transfer by generating bundle, finding and signing inputs * @@ -578,11 +592,36 @@ public class IotaAPIProxy { } 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 + * + * @method getBundle + * @param {string} transaction Hash of a tail transaction + * @returns {list} bundle Transaction objects + **/ public GetBundleResponse getBundle(String transaction) { return null; //IotaAPIUtils.getBundle(transaction); } - + + /** + * Wrapper function for getNodeInfo and getInclusionStates + * + * @method getLatestInclusion + * @param {array} hashes + * @returns {function} callback + * @returns {array} state + **/ + public GetInclusionStateResponse getLatestInclusion(String[] hashes) { + GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); + if (getNodeInfoResponse == null) return null; + + String[] latestMilestone = {getNodeInfoResponse.getLatestSolidSubtangleMilestone()}; + + return getInclusionStates(hashes, latestMilestone); + } + public static class Builder { String protocol, host, port; diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 43b4c94..ffb52ac 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -169,4 +169,15 @@ public class IotaAPIProxyTest { public void shouldSendTrytes() { proxy.sendTrytes(TEST_TRYTES, 18); } + + @Test + public void shouldGetLastInclusionState() { + GetInclusionStateResponse res = proxy.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()); + } } \ No newline at end of file From 3f8922a089a64779df877b9d1c9993b5ed6b0844 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 22 Dec 2016 18:47:41 +0100 Subject: [PATCH 041/111] added findTransactionObjects --- src/main/java/jota/IotaAPIProxy.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 7946d67..7eabbf6 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -336,6 +336,16 @@ public class IotaAPIProxy { return trxs; } + public List findTransactionObjects(String[] input) { + FindTransactionResponse ftr = findTransactions(input, null, null, null); + if (ftr == null || ftr.getHashes() == null) + + return null; + + // get the transaction objects of the transactions + return getTransactionsObjects(ftr.getHashes()); + } + /** * Wrapper function for findTransactions, getTrytes and transactionObjects * Returns the transactionObject of a transaction hash. The input can be a valid From 5881879f7846163311b83292165879c1a98e43c7 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 22 Dec 2016 19:34:31 +0100 Subject: [PATCH 042/111] added documentation --- src/main/java/jota/IotaAPIProxy.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 7eabbf6..ef62bec 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -336,6 +336,16 @@ public class IotaAPIProxy { return trxs; } + /** + * Wrapper function for findTransactions, getTrytes and transactionObjects + * Returns the transactionObject of a transaction hash. The input can be a valid + * findTransactions input + * + * @param {object} input + * @method getTransactionsObjects + * @returns {function} callback + * @returns {object} success + **/ public List findTransactionObjects(String[] input) { FindTransactionResponse ftr = findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) From b1c75bf0def18670b3ca52ce2b9dc01ea4e3dd94 Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 23 Dec 2016 09:54:16 +0100 Subject: [PATCH 043/111] fixed NullPoointer --- src/main/java/jota/IotaAPIProxy.java | 8 +++-- src/main/java/jota/utils/Converter.java | 41 ++++++++++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index ef62bec..6ac88d2 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -577,10 +577,12 @@ public class IotaAPIProxy { // Calls getBalances and formats the output // returns the final inputsObject then - public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, - final List balances, long threshold, int start, int end) { + public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, List balances, long threshold, int start, int end) { - GetBalancesResponse bres = getBalances(100, addresses); + if (balances == null || balances.isEmpty()) { + GetBalancesResponse getBalancesResponse = getBalances(100, addresses); + balances = Arrays.asList(getBalancesResponse.getBalances()); + } // If threshold defined, keep track of whether reached or not // else set default to true diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 90550e7..4276b08 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -2,14 +2,12 @@ package jota.utils; import jota.model.Transaction; import jota.pow.Curl; - -import java.util.Arrays; -import java.util.Optional; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Arrays; + public class Converter { private static final Logger log = LoggerFactory.getLogger(Converter.class); @@ -69,12 +67,39 @@ public class Converter { } public static int[] trits(final String trytes) { - final int[] trits = new int[trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE]; - for (int i = 0; i < trytes.length(); i++) { - System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); - } + if (InputValidator.isValue(trytes)) { + + int value = Integer.parseInt(trytes); + + long absoluteValue = value < 0 ? -value : value; + + while (absoluteValue > 0) { + + int remainder = (int) (absoluteValue % RADIX); + absoluteValue /= RADIX; + + if (remainder > MAX_TRIT_VALUE) { + remainder = MIN_TRIT_VALUE; + absoluteValue++; + } + + trits[trits.length] = remainder; + } + if (value < 0) { + + for (int i = 0; i < trits.length; i++) { + + trits[i] = -trits[i]; + } + } + } else { + + for (int i = 0; i < trytes.length(); i++) { + System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); + } + } return trits; } From a976e48f6b599b11737e184b08f01dce629340a1 Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 23 Dec 2016 18:34:27 +0100 Subject: [PATCH 044/111] added replayTransfer --- src/main/java/jota/IotaAPIProxy.java | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 6ac88d2..6dceab3 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -285,7 +285,7 @@ public class IotaAPIProxy { * @param {array} trytes * @param {int} depth * @param {int} minWeightMagnitude - * @return + * @return */ public List sendTrytes(final String trytes, final int minWeightMagnitude) { @@ -627,6 +627,30 @@ public class IotaAPIProxy { return null; //IotaAPIUtils.getBundle(transaction); } + /** + * 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 + **/ + public List replayTransfer(String transaction, int depth, int minWeightMagnitude) { + + List bundleTrytes = new ArrayList<>(); + + GetBundleResponse bundle = getBundle(transaction); + + for (Transaction element : bundle.getTransactions()) { + + bundleTrytes.add(IotaAPIUtils.transactionTrytes(element)); + } + + return sendTrytes(bundleTrytes, minWeightMagnitude); + } + /** * Wrapper function for getNodeInfo and getInclusionStates * From 9a327a6a43fe1851e2a43e9489ce2a0f9d1e5b54 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 24 Dec 2016 10:38:07 +0100 Subject: [PATCH 045/111] extended InputValidatorTest --- src/test/java/jota/InputValidatorTest.java | 29 ++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/test/java/jota/InputValidatorTest.java b/src/test/java/jota/InputValidatorTest.java index 5f4795e..b898baf 100644 --- a/src/test/java/jota/InputValidatorTest.java +++ b/src/test/java/jota/InputValidatorTest.java @@ -1,8 +1,12 @@ package jota; +import jota.model.Transfer; import jota.utils.InputValidator; import org.junit.Test; +import java.util.ArrayList; +import java.util.List; + import static org.junit.Assert.assertEquals; /** @@ -11,8 +15,11 @@ import static org.junit.Assert.assertEquals; public class InputValidatorTest { private static final String TEST_ADDRESS_WITHOUT_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; + private static final String TEST_ADDRESS_WITH_CHECKSUM = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA"; private static final String TEST_TRYTES = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999"; - + private static final String TEST_HASH = "OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999"; + private static final String TEST_MESSAGE = "JOTA"; + private static final String TEST_TAG = "JOTASPAM9999999999999999999"; @Test public void shouldIsAddress() { assertEquals(InputValidator.isAddress(TEST_ADDRESS_WITHOUT_CHECKSUM), true); @@ -27,4 +34,22 @@ public class InputValidatorTest { public void shouldIsTrytes() { assertEquals(InputValidator.isTrytes(TEST_TRYTES, TEST_TRYTES.length()), true); } -} + + @Test + public void shouldIsValue() { + assertEquals(InputValidator.isValue("1234"), true); + } + + @Test + public void shouldIsArrayOfHashes() { + assertEquals(InputValidator.isArrayOfHashes(new String[]{TEST_HASH, TEST_HASH}), true); + } + + @Test + public void shouldIsTransfersCollectionCorrect() { + 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, 0, TEST_MESSAGE, TEST_TAG)); + assertEquals(InputValidator.isTransfersCollectionCorrect(transfers), true); + } +} \ No newline at end of file From ad486446ada716b240045e4dd7be568236dcfd76 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 24 Dec 2016 10:55:33 +0100 Subject: [PATCH 046/111] fixed merge conflict --- src/main/java/jota/IotaAPIProxy.java | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 6dceab3..173bda8 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -335,27 +335,7 @@ public class IotaAPIProxy { } return trxs; } - - /** - * Wrapper function for findTransactions, getTrytes and transactionObjects - * Returns the transactionObject of a transaction hash. The input can be a valid - * findTransactions input - * - * @param {object} input - * @method getTransactionsObjects - * @returns {function} callback - * @returns {object} success - **/ - public List findTransactionObjects(String[] input) { - FindTransactionResponse ftr = findTransactions(input, null, null, null); - if (ftr == null || ftr.getHashes() == null) - - return null; - - // get the transaction objects of the transactions - return getTransactionsObjects(ftr.getHashes()); - } - + /** * Wrapper function for findTransactions, getTrytes and transactionObjects * Returns the transactionObject of a transaction hash. The input can be a valid From 6471467ade6f616a996e676c067dfb8d88a3a738 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 24 Dec 2016 14:07:49 +0100 Subject: [PATCH 047/111] Bugfixes --- src/main/java/jota/IotaAPIProxy.java | 6 ++-- src/main/java/jota/model/Bundle.java | 21 ++++---------- src/main/java/jota/utils/Converter.java | 30 +++++++++++++++++++- src/main/java/jota/utils/InputValidator.java | 3 +- src/main/java/jota/utils/IotaAPIUtils.java | 23 +++++---------- 5 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 173bda8..d9c50c2 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -255,7 +255,7 @@ public class IotaAPIProxy { getTransfers sendTransfer getBundle - + getTransactionsObjects findTransactionObjects @@ -335,7 +335,7 @@ public class IotaAPIProxy { } return trxs; } - + /** * Wrapper function for findTransactions, getTrytes and transactionObjects * Returns the transactionObject of a transaction hash. The input can be a valid @@ -628,7 +628,7 @@ public class IotaAPIProxy { bundleTrytes.add(IotaAPIUtils.transactionTrytes(element)); } - return sendTrytes(bundleTrytes, minWeightMagnitude); + return sendTrytes(bundleTrytes.get(0), minWeightMagnitude); } /** diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 90d966d..4f33350 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -60,25 +60,14 @@ public class Bundle { for (int i = 0; i < this.getTransactions().size(); i++) { - int[] valueTrits = Converter.trits(this.getTransactions().get(i).getValue()); - while (valueTrits.length < 81) { - valueTrits[valueTrits.length] = 0; - } + int[] valueTrits = Converter.trits(this.getTransactions().get(i).getValue(),81); - int[] timestampTrits = Converter.trits(this.getTransactions().get(i).getTimestamp()); - while (timestampTrits.length < 27) { - timestampTrits[timestampTrits.length] = 0; - } + int[] timestampTrits = Converter.trits(this.getTransactions().get(i).getTimestamp(), 27); - int[] currentIndexTrits = Converter.trits(this.getTransactions().get(i).setCurrentIndex("" + i)); - while (currentIndexTrits.length < 27) { - currentIndexTrits[currentIndexTrits.length] = 0; - } + int[] currentIndexTrits = Converter.trits(this.getTransactions().get(i).setCurrentIndex("" + i), 27); + + int[] lastIndexTrits = Converter.trits(this.getTransactions().get(i).setLastIndex("" + (this.getTransactions().size() - 1)), 27); - int[] lastIndexTrits = Converter.trits(this.getTransactions().get(i).setLastIndex("" + (this.getTransactions().size() - 1))); - while (lastIndexTrits.length < 27) { - lastIndexTrits[lastIndexTrits.length] = 0; - } 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); diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 4276b08..ec85c8f 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -7,6 +7,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; public class Converter { @@ -66,6 +68,30 @@ public class Converter { } } + public static int[] convertToIntArray(List integers) + { + int[] ret = new int[integers.size()]; + for (int i=0; i < ret.length; i++) + { + ret[i] = integers.get(i).intValue(); + } + return ret; + } + + public static int[] trits(final String trytes, int length) { + int[] trits = trits(trytes); + + List tritsList = new LinkedList<>(); + + for(int i : trits) + tritsList.add(i); + + while(tritsList.size() < length) + tritsList.add(0); + + return convertToIntArray(tritsList); + } + public static int[] trits(final String trytes) { final int[] trits = new int[trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE]; @@ -75,6 +101,8 @@ public class Converter { long absoluteValue = value < 0 ? -value : value; + int position = 0; + while (absoluteValue > 0) { int remainder = (int) (absoluteValue % RADIX); @@ -85,7 +113,7 @@ public class Converter { absoluteValue++; } - trits[trits.length] = remainder; + trits[position++] = remainder; } if (value < 0) { diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 6e85443..74592cf 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -33,7 +33,8 @@ public class InputValidator { } public static boolean isArrayOfHashes(String[] hashes) { - if (hashes == null) return false; + if (hashes == null) + return false; for (String hash : hashes) { // Check if address with checksum diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 617f014..d790e82 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -44,25 +44,16 @@ public class IotaAPIUtils { } public static String transactionTrytes(Transaction trx) { - int[] valueTrits = Converter.trits(trx.getValue()); - while (valueTrits.length < 81) { - valueTrits[valueTrits.length] = 0; - } + int[] valueTrits = Converter.trits(trx.getValue(), 81); - int[] timestampTrits = Converter.trits(trx.getTimestamp()); - while (timestampTrits.length < 27) { - timestampTrits[timestampTrits.length] = 0; - } + int[] timestampTrits = Converter.trits(trx.getTimestamp(), 27); - int[] currentIndexTrits = Converter.trits(trx.getTimestamp()); - while (currentIndexTrits.length < 27) { - currentIndexTrits[currentIndexTrits.length] = 0; - } - int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex()); - while (lastIndexTrits.length < 27) { - lastIndexTrits[lastIndexTrits.length] = 0; - } + int[] currentIndexTrits = Converter.trits(trx.getTimestamp(), 27); + + + int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex(), 27); + return trx.getSignatureFragments() + trx.getAddress() From 39db0fa897551d83646d3cef0cd755c3aad84df2 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 24 Dec 2016 14:25:08 +0100 Subject: [PATCH 048/111] fix --- src/main/java/jota/IotaAPIProxy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index d9c50c2..52af878 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -495,10 +495,10 @@ public class IotaAPIProxy { List trxb = bundle.getTransactions(); List bundleTrytes = new ArrayList<>(); + for (Transaction tx : trxb) { - jota.utils.IotaAPIUtils.transactionTrytes(tx); + bundleTrytes.add(jota.utils.IotaAPIUtils.transactionTrytes(tx)); } - Collections.reverse(bundleTrytes); return bundleTrytes; } } From 5a8e3a7222df9a27c9913ba12d49d83189ca9ef1 Mon Sep 17 00:00:00 2001 From: AZ Date: Sat, 24 Dec 2016 14:36:44 +0100 Subject: [PATCH 049/111] WIP (once again) --- src/main/java/jota/IotaAPIProxy.java | 187 ++++++++++++----------- src/main/java/jota/utils/Converter.java | 2 +- src/test/java/jota/IotaAPIProxyTest.java | 7 +- 3 files changed, 104 insertions(+), 92 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index d9c50c2..80b920c 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -26,13 +26,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 @@ -174,9 +174,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 +215,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 +227,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 +239,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 +263,13 @@ public class IotaAPIProxy { broadcastBundle getAccountData */ - + /** - * * @param trytes * @return a StoreTransactionsResponse */ - public StoreTransactionsResponse broadcastAndStore(final String ... trytes) { - + public StoreTransactionsResponse broadcastAndStore(final String... trytes) { + try { broadcastTransactions(trytes); } catch (Exception e) { @@ -279,31 +278,32 @@ 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) { - + 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)); } @@ -311,15 +311,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)) { @@ -327,9 +327,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)); } @@ -357,18 +357,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 @@ -379,7 +379,7 @@ public class IotaAPIProxy { // Create a new bundle final Bundle bundle = new Bundle(); final List signatureFragments = new ArrayList<>(); - + int totalValue = 0; String tag; @@ -399,7 +399,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()); @@ -443,7 +443,7 @@ public class IotaAPIProxy { // Case 1: user provided inputs // Validate the inputs by calling getBalances - if (!inputs.isEmpty()) { + if (inputs != null && !inputs.isEmpty()) { // Get list if addresses of the provided inputs List inputsAddresses = new ArrayList<>(); @@ -453,10 +453,11 @@ public class IotaAPIProxy { GetBalancesResponse resbalances = getBalances(100, inputsAddresses); 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; @@ -496,24 +497,31 @@ public class IotaAPIProxy { List trxb = bundle.getTransactions(); List bundleTrytes = new ArrayList<>(); for (Transaction tx : trxb) { - jota.utils.IotaAPIUtils.transactionTrytes(tx); + bundleTrytes.add(jota.utils.IotaAPIUtils.transactionTrytes(tx)); } Collections.reverse(bundleTrytes); return bundleTrytes; } } - + + 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 trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), minWeightMagnitude); + return trxs.toArray(new Transaction[trxs.size()]); + } + /** - * 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 @@ -566,18 +574,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; @@ -591,31 +600,31 @@ 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); } /** - * 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) { @@ -628,16 +637,16 @@ public class IotaAPIProxy { bundleTrytes.add(IotaAPIUtils.transactionTrytes(element)); } - return sendTrytes(bundleTrytes.get(0), minWeightMagnitude); + 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(); diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index ec85c8f..5e76567 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -143,7 +143,7 @@ public class Converter { remainder = MIN_TRIT_VALUE; absoluteValue++; } - destination[offset + i] = remainder; + destination[offset +i ] = remainder; } if (value < 0) { diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index ffb52ac..6202ba6 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; /** @@ -161,8 +162,10 @@ public class IotaAPIProxyTest { @Test public void shouldPrepareTransfer() { List transfers = new ArrayList<>(); - transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITH_CHECKSUM, 0, TEST_MESSAGE, TEST_TAG)); - proxy.prepareTransfers(TEST_SEED, transfers, null, null); + transfers.add(new jota.model.Transfer("SEOOMCIJRDPDYDXVMUVUJPUGMNO9GGKYRTQZYPUXBKTBFWMMGXCLYPASCXF9DXEXZBVXZYZOPVGGDHJFJ", 1, TEST_MESSAGE, TEST_TAG)); + List trytes = proxy.prepareTransfers("IHDEENZYITYVYSPKAURUZAQKGVJEREFDJMYTANNXXGPZ9GJWTEOJJ9IPMXOGZNQLSNMFDSQOTZAEETUEA", transfers, null, null); + assertNotNull(trytes); + assertThat(trytes.isEmpty(), Is.is(false)); } @Test From edabd0ec387d76efd5972beb74224977c7229529 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 24 Dec 2016 14:45:08 +0100 Subject: [PATCH 050/111] added sednTransfer --- src/main/java/jota/IotaAPIProxy.java | 17 +++++++++++------ src/test/java/jota/IotaAPIProxyTest.java | 8 ++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 52af878..5c0c47d 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -287,8 +287,7 @@ public class IotaAPIProxy { * @param {int} minWeightMagnitude * @return */ - public List sendTrytes(final String trytes, final int minWeightMagnitude) { - + public List sendTrytes(final String[] trytes, final int minWeightMagnitude) { final GetTransactionsToApproveResponse txs = getTransactionsToApprove(minWeightMagnitude); // attach to tangle - do pow @@ -443,7 +442,7 @@ public class IotaAPIProxy { // Case 1: user provided inputs // Validate the inputs by calling getBalances - if (!inputs.isEmpty()) { + if (inputs != null && !inputs.isEmpty()) { // Get list if addresses of the provided inputs List inputsAddresses = new ArrayList<>(); @@ -453,7 +452,6 @@ public class IotaAPIProxy { GetBalancesResponse resbalances = getBalances(100, inputsAddresses); String[] balances = resbalances.getBalances(); - List confirmedInputs = new ArrayList<>(); int totalBalance = 0; int i = 0; @@ -502,7 +500,7 @@ public class IotaAPIProxy { return bundleTrytes; } } - + /** * Gets the inputs of a seed * @@ -628,7 +626,7 @@ public class IotaAPIProxy { bundleTrytes.add(IotaAPIUtils.transactionTrytes(element)); } - return sendTrytes(bundleTrytes.get(0), minWeightMagnitude); + return sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), minWeightMagnitude); } /** @@ -648,6 +646,13 @@ public class IotaAPIProxy { return getInclusionStates(hashes, latestMilestone); } + 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 trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), minWeightMagnitude); + return trxs.toArray(new Transaction[trxs.size()]); + } + public static class Builder { String protocol, host, port; diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index ffb52ac..02ab732 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -6,6 +6,7 @@ import jota.dto.response.*; import jota.model.Transfer; import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -162,12 +163,15 @@ public class IotaAPIProxyTest { public void shouldPrepareTransfer() { List transfers = new ArrayList<>(); transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITH_CHECKSUM, 0, TEST_MESSAGE, TEST_TAG)); - proxy.prepareTransfers(TEST_SEED, transfers, null, null); + transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITH_CHECKSUM, 1, TEST_MESSAGE, TEST_TAG)); + List trytes = proxy.prepareTransfers(TEST_SEED, transfers, null, null); + Assert.assertNotNull(trytes); + assertThat(trytes.isEmpty(), Is.is(false)); } @Test public void shouldSendTrytes() { - proxy.sendTrytes(TEST_TRYTES, 18); + proxy.sendTrytes(new String[]{TEST_TRYTES}, 18); } @Test From 11bb41a88965a8b722555a42555b1675dddbdd66 Mon Sep 17 00:00:00 2001 From: AZ Date: Tue, 27 Dec 2016 19:23:36 +0100 Subject: [PATCH 051/111] 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; From 8eb007993bc9edad08e26bc0093687f4ec151ad9 Mon Sep 17 00:00:00 2001 From: pinpong Date: Tue, 27 Dec 2016 23:51:12 +0100 Subject: [PATCH 052/111] added tests --- src/test/java/jota/IotaAPIProxyTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 02ab732..e8b9299 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -3,6 +3,9 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; +import jota.error.ArgumentException; +import jota.error.InvalidBundleException; +import jota.error.InvalidSignatureException; import jota.model.Transfer; import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; @@ -184,4 +187,15 @@ public class IotaAPIProxyTest { public void shouldFindTransactionObjects() { assertThat(proxy.findTransactionObjects(new String[]{TEST_ADDRESS_WITH_CHECKSUM}), IsNull.notNullValue()); } + + @Test + public void shouldGetBundle() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + assertThat(proxy.getBundle(TEST_HASH), IsNull.notNullValue()); + } + + @Test + public void shouldGetTrasfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + assertThat(proxy.getTransfers(TEST_SEED, 0, 2, true), IsNull.notNullValue()); + assertThat(proxy.getTransfers(TEST_SEED, 0, 2, false), IsNull.notNullValue()); + } } \ No newline at end of file From 0d32622d481507923d86d7e4759d5f88507157ea Mon Sep 17 00:00:00 2001 From: pinpong Date: Wed, 28 Dec 2016 14:19:24 +0100 Subject: [PATCH 053/111] fix --- src/main/java/jota/IotaAPIProxy.java | 4 ++-- .../jota/dto/response/GetBundleResponse.java | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index f02a19c..5c036b6 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -693,7 +693,7 @@ public class IotaAPIProxy { * @method getBundle * @returns {list} bundle Transaction objects **/ - public Bundle getBundle(String transaction) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + public GetBundleResponse getBundle(String transaction) throws ArgumentException, InvalidBundleException, InvalidSignatureException { Bundle bundle = traverseBundle(transaction, null, null); if (bundle == null) { @@ -762,7 +762,7 @@ public class IotaAPIProxy { if (!isValidSignature) throw new InvalidSignatureException(); } - return bundle; + return GetBundleResponse.create(bundle.getTransactions()); } /** diff --git a/src/main/java/jota/dto/response/GetBundleResponse.java b/src/main/java/jota/dto/response/GetBundleResponse.java index 34ffb89..eac6ed8 100644 --- a/src/main/java/jota/dto/response/GetBundleResponse.java +++ b/src/main/java/jota/dto/response/GetBundleResponse.java @@ -7,17 +7,16 @@ import java.util.List; public class GetBundleResponse extends AbstractResponse { - public GetBundleResponse(){ - - } - - public GetBundleResponse(List trxs){ - this.transactions = trxs; - } - private List transactions = new ArrayList<>(); + public static GetBundleResponse create (List transactions){ + GetBundleResponse res = new GetBundleResponse(); + res.transactions = transactions; + return res; + } + + public List getTransactions() { return transactions; } -} +} \ No newline at end of file From a66a9afb8bb71b35c4fff5683df26480628aca58 Mon Sep 17 00:00:00 2001 From: pinpong Date: Wed, 28 Dec 2016 14:24:36 +0100 Subject: [PATCH 054/111] fix --- src/main/java/jota/IotaAPIProxy.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 5c036b6..9a2ee1c 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -326,7 +326,9 @@ public class IotaAPIProxy { GetInclusionStateResponse gisr = getLatestInclusion(tailTxArray); if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) return null; for (String trx : tailTxArray) { - Bundle gbr = getBundle(trx); + + GetBundleResponse bundleResponse = getBundle(trx); + 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)]; @@ -779,8 +781,8 @@ public class IotaAPIProxy { List bundleTrytes = new ArrayList<>(); - Bundle bundle = getBundle(transaction); - + GetBundleResponse bundleResponse = getBundle(transaction); + Bundle bundle = new Bundle(bundleResponse.getTransactions(), bundleResponse.getTransactions().size()); for (Transaction element : bundle.getTransactions()) { bundleTrytes.add(Converter.transactionTrytes(element)); From 72d99f09938ad44be2d77b5ddf1d59f038e8d49b Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 28 Dec 2016 14:26:30 +0100 Subject: [PATCH 055/111] added getBundle, traverseBundle, bundleFromAddresses - pls test & verify --- src/main/java/jota/utils/IotaAPIUtils.java | 59 +++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 3116681..91d1a31 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -1,9 +1,6 @@ package jota.utils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,8 +40,58 @@ public class IotaAPIUtils { return address; } - public static List signInputsAndReturn(final String seed, - final List inputs, + public static List addRemainder(final String seed, + final List inputs, + final Bundle bundle, + final String tag, + final long totalValue, + final String remainderAddress, + final List signatureFragments) { + for (int i = 0; i < inputs.size(); i++) { + long thisBalance = inputs.get(i).getBalance(); + long totalTransferValue = totalValue; + long toSubtract = 0 - thisBalance; + long timestamp = (new Date()).getTime(); + + // Add input as bundle entry + bundle.addEntry(2, inputs.get(i).getAddress(), toSubtract, tag, timestamp); + // If there is a remainder value + // Add extra output to send remaining funds to + + if (thisBalance >= totalTransferValue) { + long remainder = thisBalance - totalTransferValue; + + // If user has provided remainder address + // Use it to send remaining funds to + if (remainder > 0 && remainderAddress != null) { + // Remainder bundle entry + bundle.addEntry(1, remainderAddress, remainder, tag, timestamp); + // Final function for signing inputs + return signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } else if (remainder > 0) { + // Generate a new Address by calling getNewAddress + String address = newAddress(seed, 0, false); + // Remainder bundle entry + bundle.addEntry(1, address, remainder, tag, timestamp); + // Final function for signing inputs + return signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } else { + // If there is no remainder, do not add transaction to bundle + // simply sign and return + return signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } + + // If multiple inputs provided, subtract the totalTransferValue by + // the inputs balance + } else { + totalTransferValue -= thisBalance; + } + + } + } + + public static List signInputsAndReturn(final String seed, + final List inputs, final Bundle bundle, final List signatureFragments) { bundle.finalize(); From 15fda3f488794f9396f7029d22c4593beb7e77ea Mon Sep 17 00:00:00 2001 From: pinpong Date: Wed, 28 Dec 2016 14:59:33 +0100 Subject: [PATCH 056/111] added GetTransferResponse and SendTransferResponse --- src/main/java/jota/IotaAPIProxy.java | 12 ++++----- .../dto/response/GetTransferResponse.java | 25 +++++++++++++++++++ .../dto/response/SendTransferResponse.java | 24 ++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/main/java/jota/dto/response/GetTransferResponse.java create mode 100644 src/main/java/jota/dto/response/SendTransferResponse.java diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 9a2ee1c..dc88082 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -270,13 +270,13 @@ public class IotaAPIProxy { * @method getTransfers * @param {string} seed * @param {object} options - * @property {int} start Starting key index + * @param {function} callback + * @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 { + public GetTransferResponse 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; @@ -287,7 +287,7 @@ public class IotaAPIProxy { 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 GetTransferResponse.create(bundlesFromAddresses(gnr.getAddresses().toArray(new String[gnr.getAddresses().size()]), inclusionStates)); } return null; } @@ -808,11 +808,11 @@ public class IotaAPIProxy { return getInclusionStates(hashes, latestMilestone); } - public Transaction[] sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, Input[] inputs, String address) { + public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, Input[] inputs, String address) { 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()]); + return SendTransferResponse.create(trxs.toArray(new Transaction[trxs.size()])); } /** diff --git a/src/main/java/jota/dto/response/GetTransferResponse.java b/src/main/java/jota/dto/response/GetTransferResponse.java new file mode 100644 index 0000000..6c231ec --- /dev/null +++ b/src/main/java/jota/dto/response/GetTransferResponse.java @@ -0,0 +1,25 @@ +package jota.dto.response; + +import jota.model.Bundle; +import jota.model.Transfer; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by pinpong on 28.12.16. + */ +public class GetTransferResponse { + + private List transfers = new ArrayList<>(); + + public static GetTransferResponse create(Bundle[] transfers) { + GetTransferResponse res = new GetTransferResponse(); + res.transfers = transfers; + return res; + } + + public List getTransfers() { + return transfers; + } +} diff --git a/src/main/java/jota/dto/response/SendTransferResponse.java b/src/main/java/jota/dto/response/SendTransferResponse.java new file mode 100644 index 0000000..8067c34 --- /dev/null +++ b/src/main/java/jota/dto/response/SendTransferResponse.java @@ -0,0 +1,24 @@ +package jota.dto.response; + +/** + * Created by pinpong on 28.12.16. + */ +public class SendTransferResponse { + + private Boolean successfully; + + public static SendTransferResponse create(Boolean successfully) { + SendTransferResponse res = new SendTransferResponse(); + res.successfully = successfully; + return res; + } + + public Boolean getSuccessfully() { + return successfully; + } + + public void setSuccessfully(Boolean successfully) { + this.successfully = successfully; + } + +} From d87159c2f4df2702aadc0387c5c008e6e6255036 Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 28 Dec 2016 18:18:28 +0100 Subject: [PATCH 057/111] fixed sendtransfer --- src/main/java/jota/IotaAPIProxy.java | 80 +++++++++++++++---- .../dto/response/GetTransferResponse.java | 2 +- src/main/java/jota/model/Bundle.java | 11 ++- src/main/java/jota/utils/Converter.java | 24 +++--- src/main/java/jota/utils/IotaAPIUtils.java | 52 +----------- 5 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index dc88082..ed8ef82 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -216,7 +216,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<>(); + List allAddresses = new ArrayList<>(); // If total number of addresses to generate is supplied, simply generate // and return the list of all addresses @@ -241,7 +241,7 @@ public class IotaAPIProxy { // If !returnAll return only the last address that was generated if (!returnAll) { - allAddresses.subList(0, allAddresses.size() - 1).clear(); + allAddresses = allAddresses.subList(allAddresses.size() - 2, allAddresses.size() - 1); } return GetNewAddressResponse.create(allAddresses); } @@ -267,14 +267,14 @@ public class IotaAPIProxy { */ /** - * @method getTransfers - * @param {string} seed - * @param {object} options - * @param {function} callback - * @property {int} start Starting key index - * @property {int} end Ending key index - * @property {bool} inclusionStates returns confirmation status of all transactions - * @returns {object} success + * @param {string} seed + * @param {object} options + * @param {function} callback + * @method getTransfers + * @property {int} start Starting key index + * @property {int} end Ending key index + * @property {bool} inclusionStates returns confirmation status of all transactions + * @returns {object} success **/ public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { start = start != null ? 0 : start; @@ -292,7 +292,7 @@ public class IotaAPIProxy { return null; } - public Bundle[] bundlesFromAddresses(String[] addresses, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException{ + public Bundle[] bundlesFromAddresses(String[] addresses, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { List trxs = findTransactionObjects(addresses); // set of tail transactions @@ -808,11 +808,11 @@ public class IotaAPIProxy { return getInclusionStates(hashes, latestMilestone); } - public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, Transfer[] transactions, Input[] inputs, String address) { + public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, final List transfers, Input[] inputs, String address) { - List trytes = prepareTransfers(seed, Arrays.asList(transactions), address, inputs == null ? null : Arrays.asList(inputs)); + List trytes = prepareTransfers(seed, transfers, address, inputs == null ? null : Arrays.asList(inputs)); List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), minWeightMagnitude); - return SendTransferResponse.create(trxs.toArray(new Transaction[trxs.size()])); + return SendTransferResponse.create(true); } /** @@ -861,6 +861,58 @@ public class IotaAPIProxy { } } + public List addRemainder(final String seed, + final List inputs, + final Bundle bundle, + final String tag, + final long totalValue, + final String remainderAddress, + final List signatureFragments) { + for (int i = 0; i < inputs.size(); i++) { + long thisBalance = inputs.get(i).getBalance(); + long totalTransferValue = totalValue; + long toSubtract = 0 - thisBalance; + long timestamp = (new Date()).getTime(); + + // Add input as bundle entry + bundle.addEntry(2, inputs.get(i).getAddress(), toSubtract, tag, timestamp); + // If there is a remainder value + // Add extra output to send remaining funds to + + if (thisBalance >= totalTransferValue) { + long remainder = thisBalance - totalTransferValue; + + // If user has provided remainder address + // Use it to send remaining funds to + if (remainder > 0 && remainderAddress != null) { + // Remainder bundle entry + bundle.addEntry(1, remainderAddress, remainder, tag, timestamp); + // Final function for signing inputs + return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } else if (remainder > 0) { + // Generate a new Address by calling getNewAddress + + GetNewAddressResponse res = getNewAddress(seed, 0, false, 0, false); + // Remainder bundle entry + bundle.addEntry(1, res.getAddresses().get(0), remainder, tag, timestamp); + + // Final function for signing inputs + return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } else { + // If there is no remainder, do not add transaction to bundle + // simply sign and return + return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + } + + // If multiple inputs provided, subtract the totalTransferValue by + // the inputs balance + } else { + totalTransferValue -= thisBalance; + } + } + return null; + } + public static class Builder { String protocol, host, port; diff --git a/src/main/java/jota/dto/response/GetTransferResponse.java b/src/main/java/jota/dto/response/GetTransferResponse.java index 6c231ec..a80057b 100644 --- a/src/main/java/jota/dto/response/GetTransferResponse.java +++ b/src/main/java/jota/dto/response/GetTransferResponse.java @@ -15,7 +15,7 @@ public class GetTransferResponse { public static GetTransferResponse create(Bundle[] transfers) { GetTransferResponse res = new GetTransferResponse(); - res.transfers = transfers; + //res.transfers = transfers; return res; } diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 4f33350..29b7c7d 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -46,10 +46,9 @@ public class Bundle { for (int i = 0; i < signatureMessageLength; i++) { List transactions = new ArrayList<>(getTransactions()); - transactions.add(new Transaction(address, String.valueOf(i == 0 ? value : 0), tag, String.valueOf(timestamp))); - + Transaction trx = new Transaction(address, String.valueOf(i == 0 ? value : 0), tag, String.valueOf(timestamp)); + transactions.add(trx); setTransactions(transactions); - } } @@ -60,7 +59,7 @@ public class Bundle { for (int i = 0; i < this.getTransactions().size(); i++) { - int[] valueTrits = Converter.trits(this.getTransactions().get(i).getValue(),81); + int[] valueTrits = Converter.trits(this.getTransactions().get(i).getValue(), 81); int[] timestampTrits = Converter.trits(this.getTransactions().get(i).getTimestamp(), 27); @@ -73,7 +72,7 @@ public class Bundle { curl.absorb(t, 0, t.length); } - int[] hash = new int[90]; + int[] hash = new int[243]; curl.squeeze(hash, 0, hash.length); String hashInTrytes = Converter.trytes(hash); @@ -94,7 +93,7 @@ public class Bundle { for (int i = 0; i < this.getTransactions().size(); i++) { // Fill empty signatureMessageFragment - this.getTransactions().get(i).setSignatureFragments(signatureFragments.get(i) == null ? signatureFragments.get(i) : emptySignatureFragment); + this.getTransactions().get(i).setSignatureFragments(!signatureFragments.get(i).isEmpty() ? signatureFragments.get(i) : emptySignatureFragment); // Fill empty trunkTransaction this.getTransactions().get(i).setTrunkTransaction(emptyHash); diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index f2a10b9..6615ac9 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -93,11 +93,10 @@ public class Converter { } public static int[] trits(final String trytes) { - final int[] trits = new int[trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE]; - + final List trits = new LinkedList<>(); if (InputValidator.isValue(trytes)) { - int value = Integer.parseInt(trytes); + long value = Long.parseLong(trytes); long absoluteValue = value < 0 ? -value : value; @@ -113,22 +112,21 @@ public class Converter { absoluteValue++; } - trits[position++] = remainder; + trits.add(position++,remainder); } if (value < 0) { - - for (int i = 0; i < trits.length; i++) { - - trits[i] = -trits[i]; + for (int i = 0; i < trits.size(); i++) { + trits.set(i,-trits.get(i)); } } } else { - + int[] d = new int[3 * trytes.length()]; for (int i = 0; i < trytes.length(); i++) { - System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, trits, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); + System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, d, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); } + return d; } - return trits; + return convertToIntArray(trits); } public static void copyTrits(final long value, final int[] destination, final int offset, final int size) { @@ -213,10 +211,10 @@ public class Converter { int[] timestampTrits = Converter.trits(trx.getTimestamp(), 27); - int[] currentIndexTrits = Converter.trits(trx.getTimestamp(), 27); + int[] currentIndexTrits = Converter.trits(trx.getCurrentIndex(), 27); - int[] lastIndexTrits = Converter.trits(trx.getCurrentIndex(), 27); + int[] lastIndexTrits = Converter.trits(trx.getLastIndex(), 27); return trx.getSignatureFragments() diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 91d1a31..9f5e144 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -2,6 +2,8 @@ package jota.utils; import java.util.*; +import jota.IotaAPIProxy; +import jota.dto.response.GetNewAddressResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,56 +42,6 @@ public class IotaAPIUtils { return address; } - public static List addRemainder(final String seed, - final List inputs, - final Bundle bundle, - final String tag, - final long totalValue, - final String remainderAddress, - final List signatureFragments) { - for (int i = 0; i < inputs.size(); i++) { - long thisBalance = inputs.get(i).getBalance(); - long totalTransferValue = totalValue; - long toSubtract = 0 - thisBalance; - long timestamp = (new Date()).getTime(); - - // Add input as bundle entry - bundle.addEntry(2, inputs.get(i).getAddress(), toSubtract, tag, timestamp); - // If there is a remainder value - // Add extra output to send remaining funds to - - if (thisBalance >= totalTransferValue) { - long remainder = thisBalance - totalTransferValue; - - // If user has provided remainder address - // Use it to send remaining funds to - if (remainder > 0 && remainderAddress != null) { - // Remainder bundle entry - bundle.addEntry(1, remainderAddress, remainder, tag, timestamp); - // Final function for signing inputs - return signInputsAndReturn(seed, inputs, bundle, signatureFragments); - } else if (remainder > 0) { - // Generate a new Address by calling getNewAddress - String address = newAddress(seed, 0, false); - // Remainder bundle entry - bundle.addEntry(1, address, remainder, tag, timestamp); - // Final function for signing inputs - return signInputsAndReturn(seed, inputs, bundle, signatureFragments); - } else { - // If there is no remainder, do not add transaction to bundle - // simply sign and return - return signInputsAndReturn(seed, inputs, bundle, signatureFragments); - } - - // If multiple inputs provided, subtract the totalTransferValue by - // the inputs balance - } else { - totalTransferValue -= thisBalance; - } - - } - } - public static List signInputsAndReturn(final String seed, final List inputs, final Bundle bundle, From cbc88dac4aaf8e64380b2f2431c67f8f7024eab5 Mon Sep 17 00:00:00 2001 From: pinpong Date: Wed, 28 Dec 2016 18:47:16 +0100 Subject: [PATCH 058/111] tests --- src/test/java/jota/IotaAPIProxyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index e8b9299..b325fe8 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -51,7 +51,7 @@ public class IotaAPIProxyTest { GetNodeInfoResponse nodeInfo = proxy.getNodeInfo(); assertThat(nodeInfo.getAppVersion(), IsNull.notNullValue()); assertThat(nodeInfo.getAppName(), IsNull.notNullValue()); - //assertThat(nodeInfo.getJreVersion(), IsNull.notNullValue()); + assertThat(nodeInfo.getJreVersion(), IsNull.notNullValue()); assertThat(nodeInfo.getJreAvailableProcessors(), IsNull.notNullValue()); assertThat(nodeInfo.getJreFreeMemory(), IsNull.notNullValue()); assertThat(nodeInfo.getJreMaxMemory(), IsNull.notNullValue()); From 356a04f4b17c035975ef7772cdd2cf21a8ca2a93 Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 28 Dec 2016 19:54:34 +0100 Subject: [PATCH 059/111] bugfixing --- src/main/java/jota/IotaAPIProxy.java | 41 +++++++++++--------- src/main/java/jota/error/BaseException.java | 5 +++ src/main/java/jota/model/Bundle.java | 2 +- src/main/java/jota/utils/Converter.java | 2 +- src/main/java/jota/utils/InputValidator.java | 3 +- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index ed8ef82..cca2217 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -287,7 +287,8 @@ public class IotaAPIProxy { GetNewAddressResponse gnr = getNewAddress(seed, start, false, end == null ? end - start : end, true); if (gnr != null && gnr.getAddresses() != null) { - return GetTransferResponse.create(bundlesFromAddresses(gnr.getAddresses().toArray(new String[gnr.getAddresses().size()]), inclusionStates)); + Bundle[] bundles = bundlesFromAddresses(gnr.getAddresses().toArray(new String[gnr.getAddresses().size()]), inclusionStates); + return GetTransferResponse.create(bundles); } return null; } @@ -322,24 +323,26 @@ public class IotaAPIProxy { // If inclusionStates, get the confirmation status // of the tail transactions, and thus the bundles + GetInclusionStateResponse gisr = null; if (inclusionStates) { - GetInclusionStateResponse gisr = getLatestInclusion(tailTxArray); + gisr = getLatestInclusion(tailTxArray); if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) return null; - for (String trx : tailTxArray) { + } + for (String trx : tailTxArray) { - GetBundleResponse bundleResponse = getBundle(trx); - 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); - } + GetBundleResponse bundleResponse = getBundle(trx); + 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); } - finalBundles.add(gbr); } + 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())) @@ -472,7 +475,7 @@ public class IotaAPIProxy { final List signatureFragments = new ArrayList<>(); int totalValue = 0; - String tag; + String tag = ""; // Iterate over all transfers, get totalValue // and prepare the signatureFragments, message and tag @@ -565,7 +568,7 @@ public class IotaAPIProxy { throw new IllegalStateException("Not enough balance"); } - return IotaAPIUtils.signInputsAndReturn(seed, confirmedInputs, bundle, signatureFragments); + return addRemainder(seed, confirmedInputs, bundle, tag, totalValue, null, signatureFragments); } // Case 2: Get inputs deterministically @@ -576,7 +579,7 @@ public class IotaAPIProxy { GetBalancesAndFormatResponse newinputs = getInputs(seed, Collections.EMPTY_LIST, 0, 0, totalValue); // If inputs with enough balance - return IotaAPIUtils.signInputsAndReturn(seed, newinputs.getInput(), bundle, signatureFragments); + return addRemainder(seed, newinputs.getInput(), bundle, tag, totalValue, null, signatureFragments); } } else { @@ -697,7 +700,7 @@ public class IotaAPIProxy { **/ public GetBundleResponse getBundle(String transaction) throws ArgumentException, InvalidBundleException, InvalidSignatureException { - Bundle bundle = traverseBundle(transaction, null, null); + Bundle bundle = traverseBundle(transaction, null, new Bundle()); if (bundle == null) { return null; } @@ -746,8 +749,8 @@ public class IotaAPIProxy { // 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]); + int[] bundleFromTrxs = new int[243]; + curl.squeeze(bundleFromTrxs); String bundleFromTxString = Converter.trytes(bundleFromTrxs); // Check if bundle hash is the same as returned by tx object @@ -852,6 +855,8 @@ public class IotaAPIProxy { // Define new trunkTransaction for search trunkTx = trx.getTrunkTransaction(); // Add transaction object to bundle + //if (bundle == null) + // bundle = new Bundle(); bundle.getTransactions().add(trx); // Continue traversing with new trunkTx diff --git a/src/main/java/jota/error/BaseException.java b/src/main/java/jota/error/BaseException.java index 2931408..972a0ac 100644 --- a/src/main/java/jota/error/BaseException.java +++ b/src/main/java/jota/error/BaseException.java @@ -1,5 +1,6 @@ package jota.error; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -14,6 +15,10 @@ public class BaseException extends Exception { public BaseException(String msg) { super(msg); + if (messages == null) { + messages = new ArrayList<>(); + } + messages.add(msg); } public BaseException(String msg, Exception cause) { diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 29b7c7d..3d0a98d 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -93,7 +93,7 @@ public class Bundle { for (int i = 0; i < this.getTransactions().size(); i++) { // Fill empty signatureMessageFragment - this.getTransactions().get(i).setSignatureFragments(!signatureFragments.get(i).isEmpty() ? signatureFragments.get(i) : emptySignatureFragment); + this.getTransactions().get(i).setSignatureFragments((signatureFragments.size() <= i || signatureFragments.get(i).isEmpty()) ? emptySignatureFragment : signatureFragments.get(i)); // Fill empty trunkTransaction this.getTransactions().get(i).setTrunkTransaction(emptyHash); diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 6615ac9..cbe95a7 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -246,7 +246,7 @@ public class Converter { } int[] transactionTrits = Converter.trits(trytes); - int[] hash = new int[90]; + int[] hash = new int[243]; final Curl curl = new Curl(); // we need a fluent Curl. diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 74592cf..90392e7 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -6,6 +6,7 @@ import org.apache.commons.lang3.StringUtils; import jota.model.Transaction; import jota.model.Transfer; +import org.apache.commons.lang3.math.NumberUtils; /** * Created by pinpong on 02.12.16. @@ -29,7 +30,7 @@ public class InputValidator { } public static boolean isValue(final String value) { - return StringUtils.isNumeric(value); + return NumberUtils.isNumber(value); } public static boolean isArrayOfHashes(String[] hashes) { From d9275f12083df25975e10ed6c4bedf95a66964eb Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 28 Dec 2016 21:03:02 +0100 Subject: [PATCH 060/111] bugfixing --- src/main/java/jota/IotaAPIProxy.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index cca2217..6a25a78 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -593,7 +593,8 @@ public class IotaAPIProxy { for (Transaction tx : trxb) { bundleTrytes.add(Converter.transactionTrytes(tx)); } - return bundleTrytes; + Collections.reverse(bundleTrytes); + return bundleTrytes ; } } @@ -735,7 +736,7 @@ public class IotaAPIProxy { sig.getSignatureFragments().add(trx.getSignatureFragments()); // Find the subsequent txs with the remaining signature fragment - for (int y = i; i < bundle.getTransactions().size() - 1; i++) { + for (int y = i; y < bundle.getTransactions().size() - 1; y++) { Transaction newBundleTx = bundle.getTransactions().get(i + 1); // Check if new tx is part of the signature fragment @@ -845,7 +846,7 @@ public class IotaAPIProxy { bundleHash = trx.getBundle(); } // If different bundle hash, return with bundle - if (bundleHash != trx.getBundle()) { + if (!bundleHash.equals(trx.getBundle())) { return bundle; } // If only one bundle element, return @@ -855,8 +856,6 @@ public class IotaAPIProxy { // Define new trunkTransaction for search trunkTx = trx.getTrunkTransaction(); // Add transaction object to bundle - //if (bundle == null) - // bundle = new Bundle(); bundle.getTransactions().add(trx); // Continue traversing with new trunkTx From 6c2ec92a25768bc0931a20155a15a16674768665 Mon Sep 17 00:00:00 2001 From: pinpong Date: Wed, 28 Dec 2016 23:27:29 +0100 Subject: [PATCH 061/111] minor --- src/main/java/jota/IotaAPIProxy.java | 10 +++++----- src/test/java/jota/IotaAPIProxyTest.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 6a25a78..205925f 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -545,8 +545,8 @@ public class IotaAPIProxy { inputsAddresses.add(i.getAddress()); } - GetBalancesResponse resbalances = getBalances(100, inputsAddresses); - String[] balances = resbalances.getBalances(); + GetBalancesResponse balancesResponse = getBalances(100, inputsAddresses); + String[] balances = balancesResponse.getBalances(); List confirmedInputs = new ArrayList<>(); int totalBalance = 0; @@ -816,7 +816,7 @@ public class IotaAPIProxy { List trytes = prepareTransfers(seed, transfers, address, inputs == null ? null : Arrays.asList(inputs)); List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), minWeightMagnitude); - return SendTransferResponse.create(true); + return SendTransferResponse.create(trxs.get(0).getPersistence()); } /** @@ -832,7 +832,7 @@ public class IotaAPIProxy { **/ public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { GetTrytesResponse gtr = getTrytes(trunkTx); - if (gtr != null & gtr.getTrytes().length != 0) { + 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"); @@ -851,7 +851,7 @@ public class IotaAPIProxy { } // If only one bundle element, return if (Integer.parseInt(trx.getLastIndex()) == 0 && Integer.parseInt(trx.getCurrentIndex()) == 0) { - return new Bundle(Arrays.asList(trx), 1); + return new Bundle(Collections.singletonList(trx), 1); } // Define new trunkTransaction for search trunkTx = trx.getTrunkTransaction(); diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index b325fe8..b2017f5 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -194,7 +194,7 @@ public class IotaAPIProxyTest { } @Test - public void shouldGetTrasfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { assertThat(proxy.getTransfers(TEST_SEED, 0, 2, true), IsNull.notNullValue()); assertThat(proxy.getTransfers(TEST_SEED, 0, 2, false), IsNull.notNullValue()); } From 7f09e45c08663994b580eb9bd56f272b81127b9b Mon Sep 17 00:00:00 2001 From: AZ Date: Thu, 29 Dec 2016 08:46:27 +0100 Subject: [PATCH 062/111] fixed value in trx object --- src/main/java/jota/IotaAPIProxy.java | 36 +++++++++++++++++++---- src/main/java/jota/model/Transaction.java | 8 +++++ src/main/java/jota/utils/Converter.java | 11 ++++++- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 205925f..16d4b30 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -305,16 +305,20 @@ public class IotaAPIProxy { if (Long.parseLong(trx.getCurrentIndex()) == 0) { tailTransactions.add(trx.getHash()); } else { - nonTailBundleHashes.add(trx.getBundle()); + if(nonTailBundleHashes.indexOf(trx.getBundle()) == -1){ + nonTailBundleHashes.add(trx.getBundle()); + } } } if (nonTailBundleHashes.isEmpty()) return null; - List bundleObjects = findTransactionObjects(addresses); + List bundleObjects = findTransactionObjectsByBundle(nonTailBundleHashes.toArray(new String[nonTailBundleHashes.size()])); for (Transaction trx : bundleObjects) { // Sort tail and nonTails if (Long.parseLong(trx.getCurrentIndex()) == 0) { - tailTransactions.add(trx.getHash()); + if(tailTransactions.indexOf(trx.getHash()) == -1) { + tailTransactions.add(trx.getHash()); + } } } @@ -443,7 +447,25 @@ public class IotaAPIProxy { public List findTransactionObjects(String[] input) { FindTransactionResponse ftr = findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) + return null; + // get the transaction objects of the transactions + return getTransactionsObjects(ftr.getHashes()); + } + + /** + * Wrapper function for findTransactions, getTrytes and transactionObjects + * Returns the transactionObject of a transaction hash. The input can be a valid + * findTransactions input + * + * @param {object} input + * @method getTransactionsObjects + * @returns {function} callback + * @returns {object} success + **/ + public List findTransactionObjectsByBundle(String[] input) { + FindTransactionResponse ftr = findTransactions(null, null, null, input); + if (ftr == null || ftr.getHashes() == null) return null; // get the transaction objects of the transactions @@ -594,7 +616,7 @@ public class IotaAPIProxy { bundleTrytes.add(Converter.transactionTrytes(tx)); } Collections.reverse(bundleTrytes); - return bundleTrytes ; + return bundleTrytes; } } @@ -725,7 +747,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)); // Check if input transaction @@ -757,6 +779,7 @@ public class IotaAPIProxy { // 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 + bundle.setLength(bundle.getTransactions().size()); if (!bundle.getTransactions().get(bundle.getLength() - 1).getCurrentIndex().equals(bundle.getTransactions().get(bundle.getLength() - 1).getLastIndex())) throw new InvalidBundleException("Invalid Bundle"); @@ -832,6 +855,9 @@ public class IotaAPIProxy { **/ public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { GetTrytesResponse gtr = getTrytes(trunkTx); + System.out.println("GetTrytesRequest "+trunkTx); + System.out.println("GetTrytesResponse "+gtr.getTrytes()[0]); + if (gtr != null && gtr.getTrytes().length != 0) { Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]); if (trx == null || trx.getBundle() == null) { diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 0f7f962..210a287 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -157,4 +157,12 @@ public class Transaction { public void setPersistence(Boolean persistence) { this.persistence = persistence; } + + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (((Transaction) obj).getHash().equals(this.getHash())) return true; + return false; + } } \ No newline at end of file diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index cbe95a7..441c6ed 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -194,6 +194,15 @@ public class Converter { return value; } + public static long longValue(final int[] trits) { + long value = 0; + + for (int i = trits.length; i-- > 0; ) { + value = value * 3 + trits[i]; + } + return value; + } + public static void increment(final int[] trits, final int size) { for (int i = 0; i < size; i++) { @@ -260,7 +269,7 @@ public class Converter { trx.setHash(Converter.trytes(hash)); trx.setSignatureFragments(trytes.substring(0, 2187)); trx.setAddress(trytes.substring(2187, 2268)); - trx.setValue("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6804, 6837))); + trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837))); trx.setTag(trytes.substring(2295, 2322)); trx.setTimestamp("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6966, 6993))); trx.setCurrentIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6993, 7020))); From fd67bb797e0043dba36096926dac3615ae326fb2 Mon Sep 17 00:00:00 2001 From: AZ Date: Thu, 29 Dec 2016 09:17:54 +0100 Subject: [PATCH 063/111] fixed value in trx object --- src/main/java/jota/IotaAPIProxy.java | 3 +-- src/main/java/jota/model/Bundle.java | 2 +- src/main/java/jota/utils/Signing.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 16d4b30..455f741 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -763,6 +763,7 @@ public class IotaAPIProxy { // Check if new tx is part of the signature fragment if (newBundleTx.getAddress().equals(address) && Long.parseLong(newBundleTx.getValue()) == 0) { + if(sig.getSignatureFragments().indexOf(newBundleTx.getSignatureFragments()) == -1) sig.getSignatureFragments().add(newBundleTx.getSignatureFragments()); } } @@ -855,8 +856,6 @@ public class IotaAPIProxy { **/ public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { GetTrytesResponse gtr = getTrytes(trunkTx); - System.out.println("GetTrytesRequest "+trunkTx); - System.out.println("GetTrytesResponse "+gtr.getTrytes()[0]); if (gtr != null && gtr.getTrytes().length != 0) { Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]); diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 3d0a98d..66db019 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -106,7 +106,7 @@ public class Bundle { } public int[] normalizedBundle(String bundleHash) { - int[] normalizedBundle = new int[33 * 27 + 27]; + int[] normalizedBundle = new int[81]; for (int i = 0; i < 3; i++) { diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index e0f2e84..1f99d7c 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -151,7 +151,7 @@ public class Signing { } // Get digests - int[] digests = new int[signatureFragments.length * 243 + 243]; + int[] digests = new int[signatureFragments.length * 243]; for (int i = 0; i < signatureFragments.length; i++) { From 6f94c90edde5cffb25d4dfe051cdb52ccfd1e670 Mon Sep 17 00:00:00 2001 From: AZ Date: Thu, 29 Dec 2016 10:24:41 +0100 Subject: [PATCH 064/111] ... --- src/main/java/jota/IotaAPIProxy.java | 17 +++++++++-------- .../jota/dto/response/GetTransferResponse.java | 6 +++--- src/main/java/jota/utils/Signing.java | 9 +++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 455f741..818b10f 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -305,18 +305,18 @@ public class IotaAPIProxy { if (Long.parseLong(trx.getCurrentIndex()) == 0) { tailTransactions.add(trx.getHash()); } else { - if(nonTailBundleHashes.indexOf(trx.getBundle()) == -1){ + if (nonTailBundleHashes.indexOf(trx.getBundle()) == -1) { nonTailBundleHashes.add(trx.getBundle()); } } } if (nonTailBundleHashes.isEmpty()) return null; - List bundleObjects = findTransactionObjectsByBundle(nonTailBundleHashes.toArray(new String[nonTailBundleHashes.size()])); + List bundleObjects = findTransactionObjectsByBundle(nonTailBundleHashes.toArray(new String[nonTailBundleHashes.size()])); for (Transaction trx : bundleObjects) { // Sort tail and nonTails if (Long.parseLong(trx.getCurrentIndex()) == 0) { - if(tailTransactions.indexOf(trx.getHash()) == -1) { + if (tailTransactions.indexOf(trx.getHash()) == -1) { tailTransactions.add(trx.getHash()); } } @@ -763,8 +763,8 @@ public class IotaAPIProxy { // Check if new tx is part of the signature fragment if (newBundleTx.getAddress().equals(address) && Long.parseLong(newBundleTx.getValue()) == 0) { - if(sig.getSignatureFragments().indexOf(newBundleTx.getSignatureFragments()) == -1) - sig.getSignatureFragments().add(newBundleTx.getSignatureFragments()); + if (sig.getSignatureFragments().indexOf(newBundleTx.getSignatureFragments()) == -1) + sig.getSignatureFragments().add(newBundleTx.getSignatureFragments()); } } signaturesToValidate.add(sig); @@ -786,10 +786,11 @@ public class IotaAPIProxy { // Validate the signatures for (int i = 0; i < signaturesToValidate.size(); i++) { + String[] signatureFragments = signaturesToValidate.get(i).getSignatureFragments().toArray(new String[signaturesToValidate.get(i).getSignatureFragments().size()]); + String address = signaturesToValidate.get(i).getAddress(); + boolean isValidSignature = Signing.validateSignatures(address, signatureFragments, bundleHash); - boolean isValidSignature = Signing.validateSignatures(signaturesToValidate.get(i).getAddress(), signaturesToValidate.get(i).getSignatureFragments().toArray(new String[signaturesToValidate.size()]), bundleHash); - - if (!isValidSignature) throw new InvalidSignatureException(); + //if (!isValidSignature) throw new InvalidSignatureException(); } return GetBundleResponse.create(bundle.getTransactions()); diff --git a/src/main/java/jota/dto/response/GetTransferResponse.java b/src/main/java/jota/dto/response/GetTransferResponse.java index a80057b..1d39537 100644 --- a/src/main/java/jota/dto/response/GetTransferResponse.java +++ b/src/main/java/jota/dto/response/GetTransferResponse.java @@ -11,15 +11,15 @@ import java.util.List; */ public class GetTransferResponse { - private List transfers = new ArrayList<>(); + private Bundle[] transfers; public static GetTransferResponse create(Bundle[] transfers) { GetTransferResponse res = new GetTransferResponse(); - //res.transfers = transfers; + res.transfers = transfers; return res; } - public List getTransfers() { + public Bundle[] getTransfers() { return transfers; } } diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 1f99d7c..2d27b42 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -127,9 +127,10 @@ public class Signing { for (int j = normalizedBundleFragment[i] + 13; j-- > 0; ) { - new Curl().reset() - .absorb(buffer) - .squeeze(buffer); + Curl jCurl = new Curl(); + jCurl.reset(); + jCurl.absorb(buffer); + jCurl.squeeze(buffer); } curl.absorb(buffer); } @@ -162,7 +163,7 @@ public class Signing { digests[i * 243 + j] = digestBuffer[j]; } } - + System.out.println(Arrays.toString(digests).replaceAll("\\s+","")); String address = Converter.trytes(address(digests)); return (expectedAddress.equals(address)); From 3d5776f3ece2d9f0bc44a1af8bb8b560f33dd69a Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 29 Dec 2016 10:32:24 +0100 Subject: [PATCH 065/111] fix --- src/main/java/jota/dto/response/GetTransferResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/jota/dto/response/GetTransferResponse.java b/src/main/java/jota/dto/response/GetTransferResponse.java index 1d39537..c780c2e 100644 --- a/src/main/java/jota/dto/response/GetTransferResponse.java +++ b/src/main/java/jota/dto/response/GetTransferResponse.java @@ -9,7 +9,7 @@ import java.util.List; /** * Created by pinpong on 28.12.16. */ -public class GetTransferResponse { +public class GetTransferResponse extends AbstractResponse { private Bundle[] transfers; From dfd5fb86db60625d115eb67ce03034355fdafd67 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 29 Dec 2016 17:54:00 +0100 Subject: [PATCH 066/111] removed unused file --- .../jota/dto/response/GetTransfersResponse.java | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/main/java/jota/dto/response/GetTransfersResponse.java diff --git a/src/main/java/jota/dto/response/GetTransfersResponse.java b/src/main/java/jota/dto/response/GetTransfersResponse.java deleted file mode 100644 index 441ccea..0000000 --- a/src/main/java/jota/dto/response/GetTransfersResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package jota.dto.response; - -import jota.model.Transfer; - -import java.util.ArrayList; -import java.util.List; - -public class GetTransfersResponse extends AbstractResponse { - - private List transfers = new ArrayList<>(); - - public List getTransfers() { - return transfers; - } -} From d216193bf3f6af67c926cfd9921d21c05fbb48c4 Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 29 Dec 2016 18:27:51 +0100 Subject: [PATCH 067/111] renamed --- .../java/jota/dto/response/GetTransferResponse.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/jota/dto/response/GetTransferResponse.java b/src/main/java/jota/dto/response/GetTransferResponse.java index c780c2e..72b9cec 100644 --- a/src/main/java/jota/dto/response/GetTransferResponse.java +++ b/src/main/java/jota/dto/response/GetTransferResponse.java @@ -1,25 +1,21 @@ package jota.dto.response; import jota.model.Bundle; -import jota.model.Transfer; - -import java.util.ArrayList; -import java.util.List; /** * Created by pinpong on 28.12.16. */ public class GetTransferResponse extends AbstractResponse { - private Bundle[] transfers; + private Bundle[] transferBundle; - public static GetTransferResponse create(Bundle[] transfers) { + public static GetTransferResponse create(Bundle[] transferBundle) { GetTransferResponse res = new GetTransferResponse(); - res.transfers = transfers; + res.transferBundle = transferBundle; return res; } public Bundle[] getTransfers() { - return transfers; + return transferBundle; } } From 7e7b7f029c053769ee9f9ca34f4ba8131fedf15c Mon Sep 17 00:00:00 2001 From: pinpong Date: Thu, 29 Dec 2016 19:10:20 +0100 Subject: [PATCH 068/111] fix --- src/main/java/jota/dto/response/SendTransferResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/jota/dto/response/SendTransferResponse.java b/src/main/java/jota/dto/response/SendTransferResponse.java index 8067c34..4eafeca 100644 --- a/src/main/java/jota/dto/response/SendTransferResponse.java +++ b/src/main/java/jota/dto/response/SendTransferResponse.java @@ -3,7 +3,7 @@ package jota.dto.response; /** * Created by pinpong on 28.12.16. */ -public class SendTransferResponse { +public class SendTransferResponse extends AbstractResponse { private Boolean successfully; From 4c83f388928d599353664a3d3be89dfd2275c50c Mon Sep 17 00:00:00 2001 From: AZ Date: Thu, 29 Dec 2016 19:55:47 +0100 Subject: [PATCH 069/111] ... --- src/main/java/jota/model/Bundle.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 66db019..457c108 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -43,12 +43,14 @@ public class Bundle { } public void addEntry(int signatureMessageLength, String address, long value, String tag, long timestamp) { - for (int i = 0; i < signatureMessageLength; i++) { + if (getTransactions() == null) { + this.transactions = new ArrayList<>(getTransactions()); + } + for (int i = 0; i < signatureMessageLength; i++) { List transactions = new ArrayList<>(getTransactions()); Transaction trx = new Transaction(address, String.valueOf(i == 0 ? value : 0), tag, String.valueOf(timestamp)); - transactions.add(trx); - setTransactions(transactions); + getTransactions().add(trx); } } From 8db0f33481a26e55cbd94f36f53c287a36a53471 Mon Sep 17 00:00:00 2001 From: AZ Date: Thu, 29 Dec 2016 22:02:29 +0100 Subject: [PATCH 070/111] fixed almost everything --- src/main/java/jota/IotaAPIProxy.java | 8 +++++--- src/main/java/jota/model/Bundle.java | 2 +- src/main/java/jota/utils/Converter.java | 17 ++++++++++++----- src/main/java/jota/utils/Signing.java | 2 +- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 818b10f..a017660 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -335,6 +335,8 @@ public class IotaAPIProxy { for (String trx : tailTxArray) { 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) { @@ -349,9 +351,9 @@ public class IotaAPIProxy { 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; + if (Long.parseLong(c1.getTransactions().get(0).getTimestamp()) > Long.parseLong(c2.getTransactions().get(0).getTimestamp())) return 1; return 0; } @@ -790,7 +792,7 @@ public class IotaAPIProxy { String address = signaturesToValidate.get(i).getAddress(); boolean isValidSignature = Signing.validateSignatures(address, signatureFragments, bundleHash); - //if (!isValidSignature) throw new InvalidSignatureException(); + if (!isValidSignature) throw new InvalidSignatureException(); } return GetBundleResponse.create(bundle.getTransactions()); diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 457c108..9efd908 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -115,7 +115,7 @@ public class Bundle { long sum = 0; for (int j = 0; j < 27; j++) { - sum += (normalizedBundle[i * 27 + j] = Converter.value(Converter.trits("" + bundleHash.charAt(i * 27 + j)))); + sum += (normalizedBundle[i * 27 + j] = Converter.value(Converter.tritsString("" + bundleHash.charAt(i * 27 + j)))); } if (sum >= 0) { diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 441c6ed..3329175 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -11,7 +11,7 @@ import java.util.LinkedList; import java.util.List; public class Converter { - + private static final Logger log = LoggerFactory.getLogger(Converter.class); private static final int RADIX = 3; @@ -91,6 +91,13 @@ public class Converter { return convertToIntArray(tritsList); } + public static int[] tritsString(final String trytes){ + int[] d = new int[3 * trytes.length()]; + for (int i = 0; i < trytes.length(); i++) { + System.arraycopy(TRYTE_TO_TRITS_MAPPINGS[Constants.TRYTE_ALPHABET.indexOf(trytes.charAt(i))], 0, d, i * NUMBER_OF_TRITS_IN_A_TRYTE, NUMBER_OF_TRITS_IN_A_TRYTE); + } + return d; + } public static int[] trits(final String trytes) { final List trits = new LinkedList<>(); @@ -238,14 +245,14 @@ public class Converter { + trx.getBranchTransaction() + trx.getNonce(); } - + public static Transaction transactionObject(final String trytes) { - + if (StringUtils.isEmpty(trytes)) { log.warn("Warning: empty trytes in input for transactionObject"); return null; } - + // validity check for (int i = 2279; i < 2295; i++) { if (trytes.charAt(i) != '9') { @@ -253,7 +260,7 @@ public class Converter { return null; } } - + int[] transactionTrits = Converter.trits(trytes); int[] hash = new int[243]; diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 2d27b42..c6110fd 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -163,7 +163,7 @@ public class Signing { digests[i * 243 + j] = digestBuffer[j]; } } - System.out.println(Arrays.toString(digests).replaceAll("\\s+","")); + //System.out.println(Arrays.toString(digests).replaceAll("\\s+","")); String address = Converter.trytes(address(digests)); return (expectedAddress.equals(address)); From 7504c1ead3ad5f804d77c7d62b009614fe47a261 Mon Sep 17 00:00:00 2001 From: AZ Date: Thu, 29 Dec 2016 22:03:41 +0100 Subject: [PATCH 071/111] added getInputsTest --- src/test/java/jota/IotaAPIProxyTest.java | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index b2017f5..8f34f1c 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -28,7 +28,8 @@ public class IotaAPIProxyTest { private static Gson gson = new GsonBuilder().create(); - private static final String TEST_SEED = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; + private static final String TEST_SEED1 = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; + private static final String TEST_SEED2 = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; 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"; @@ -140,6 +141,16 @@ public class IotaAPIProxyTest { } + @Test + public void shouldGetInputs() { + GetBalancesAndFormatResponse res = proxy.getInputs(TEST_SEED2, null, 0,0, 0); + System.out.println(res); + assertThat(res, IsNull.notNullValue()); + assertThat(res.getTotalBalance(), IsNull.notNullValue()); + assertThat(res.getInput(), IsNull.notNullValue()); + + } + @Test public void shouldGetBalances() { GetBalancesResponse res = proxy.getBalances(100, new String[]{TEST_ADDRESS_WITH_CHECKSUM}); @@ -158,7 +169,7 @@ public class IotaAPIProxyTest { @Test public void shouldCreateANewAddress() { - final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED, 0, false, 1, false); + final GetNewAddressResponse res = proxy.getNewAddress(TEST_SEED1, 0, false, 1, false); assertThat(res.getAddresses(), Is.is(Collections.singletonList(TEST_ADDRESS_WITHOUT_CHECKSUM))); } @@ -167,7 +178,7 @@ 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_SEED, transfers, null, null); + List trytes = proxy.prepareTransfers(TEST_SEED1, transfers, null, null); Assert.assertNotNull(trytes); assertThat(trytes.isEmpty(), Is.is(false)); } @@ -194,8 +205,9 @@ public class IotaAPIProxyTest { } @Test - public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { - assertThat(proxy.getTransfers(TEST_SEED, 0, 2, true), IsNull.notNullValue()); - assertThat(proxy.getTransfers(TEST_SEED, 0, 2, false), IsNull.notNullValue()); + public void shouldGetTrasfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + GetTransferResponse gtr = proxy.getTransfers(TEST_SEED1, 0, 0, true); + assertThat(gtr, IsNull.notNullValue()); + assertThat(proxy.getTransfers(TEST_SEED2, 0, 0, false), IsNull.notNullValue()); } } \ No newline at end of file From ba3dd71750973b66a7ad5722b65592813454dc0f Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 30 Dec 2016 10:03:51 +0100 Subject: [PATCH 072/111] updated tests --- src/test/java/jota/IotaAPIProxyTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 8f34f1c..9dab078 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -205,9 +205,11 @@ public class IotaAPIProxyTest { } @Test - public void shouldGetTrasfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { - GetTransferResponse gtr = proxy.getTransfers(TEST_SEED1, 0, 0, true); - assertThat(gtr, IsNull.notNullValue()); - assertThat(proxy.getTransfers(TEST_SEED2, 0, 0, false), IsNull.notNullValue()); + public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + GetTransferResponse gtr = proxy.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()); } } \ No newline at end of file From 9011339f3bbadd7dbc1f0499e6d033aeaa0114b1 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 30 Dec 2016 10:14:37 +0100 Subject: [PATCH 073/111] fixed getbalances --- src/main/java/jota/IotaAPIProxy.java | 21 --------------------- src/main/java/jota/utils/Converter.java | 6 +++--- src/test/java/jota/IotaAPIProxyTest.java | 12 +++++------- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index a017660..b8a0087 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -245,26 +245,6 @@ public class IotaAPIProxy { } return GetNewAddressResponse.create(allAddresses); } - - /* - * newAddress - * broadcastAndStore - * sendTrytes - * prepareTransfers - * getInputs - * getLatestInclusion - - getTransfers - sendTransfer - getBundle - - getTransactionsObjects - findTransactionObjects - - replayBundle - broadcastBundle - getAccountData - */ /** * @param {string} seed @@ -310,7 +290,6 @@ public class IotaAPIProxy { } } } - if (nonTailBundleHashes.isEmpty()) return null; List bundleObjects = findTransactionObjectsByBundle(nonTailBundleHashes.toArray(new String[nonTailBundleHashes.size()])); for (Transaction trx : bundleObjects) { diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 3329175..ce2d604 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -278,9 +278,9 @@ public class Converter { trx.setAddress(trytes.substring(2187, 2268)); trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837))); trx.setTag(trytes.substring(2295, 2322)); - trx.setTimestamp("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6966, 6993))); - trx.setCurrentIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 6993, 7020))); - trx.setLastIndex("" + Converter.value(Arrays.copyOfRange(transactionTrits, 7020, 7047))); + trx.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993))); + trx.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020))); + trx.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047))); trx.setBundle(trytes.substring(2349, 2430)); trx.setTrunkTransaction(trytes.substring(2430, 2511)); trx.setBranchTransaction(trytes.substring(2511, 2592)); diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 9dab078..42f487c 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -29,7 +29,7 @@ public class IotaAPIProxyTest { 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"; @@ -205,11 +205,9 @@ public class IotaAPIProxyTest { } @Test - public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { - GetTransferResponse gtr = proxy.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()); + public void shouldGetTrasfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + GetTransferResponse gtr = proxy.getTransfers(TEST_SEED2, 0, 0, true); + assertThat(gtr, IsNull.notNullValue()); + assertThat(proxy.getTransfers(TEST_SEED2, 0, 0, false), IsNull.notNullValue()); } } \ No newline at end of file From 31654ae166c9695bfa00fe2569d79e92008d5db9 Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 30 Dec 2016 10:21:45 +0100 Subject: [PATCH 074/111] updated tests --- src/test/java/jota/IotaAPIProxyTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 42f487c..774ca9c 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -205,9 +205,11 @@ public class IotaAPIProxyTest { } @Test - public void shouldGetTrasfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { - GetTransferResponse gtr = proxy.getTransfers(TEST_SEED2, 0, 0, true); - assertThat(gtr, IsNull.notNullValue()); - assertThat(proxy.getTransfers(TEST_SEED2, 0, 0, false), IsNull.notNullValue()); + public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + GetTransferResponse gtr = proxy.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()); } } \ No newline at end of file From 8ebd340c3fc36c0e3b705cf2462b6eaff08d0129 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 30 Dec 2016 10:46:01 +0100 Subject: [PATCH 075/111] better error handling for traverseBundle --- src/main/java/jota/IotaAPIProxy.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index b8a0087..c18ae60 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -315,7 +315,7 @@ public class IotaAPIProxy { GetBundleResponse bundleResponse = getBundle(trx); // TODO: review possibly dirty WA - if(bundleResponse == null) continue; + if (bundleResponse == null) continue; Bundle gbr = new Bundle(bundleResponse.getTransactions(), bundleResponse.getTransactions().size()); if (gbr != null && gbr.getTransactions() != null) { if (inclusionStates) { @@ -839,7 +839,12 @@ public class IotaAPIProxy { public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { GetTrytesResponse gtr = getTrytes(trunkTx); - if (gtr != null && gtr.getTrytes().length != 0) { + if (gtr != null) { + + 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"); @@ -868,7 +873,7 @@ public class IotaAPIProxy { // Continue traversing with new trunkTx return traverseBundle(trunkTx, bundleHash, bundle); } else { - return null; + throw new ArgumentException("Get Trytes Response was null"); } } From 368d613266357e02f00d03892556a3ecc9a57b20 Mon Sep 17 00:00:00 2001 From: pinpong Date: Fri, 30 Dec 2016 16:35:46 +0100 Subject: [PATCH 076/111] sendTransfer test --- src/test/java/jota/IotaAPIProxyTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index 774ca9c..fbfaf8b 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -29,7 +29,7 @@ public class IotaAPIProxyTest { private static Gson gson = new GsonBuilder().create(); private static final String TEST_SEED1 = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; - private static final String TEST_SEED2 = "IHDEENZYITYVYSPKAURUZAQKGVJEREFDJMYTANNXXGPZ9GJWTEOJJ9IPMXOGZNQLSNMFDSQOTZAEETUEA"; + private static final String TEST_SEED2 = "AAA999999999999999999999999999999999999999999999999999999999999999999999999999999"; 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"; @@ -212,4 +212,12 @@ public class IotaAPIProxyTest { GetTransferResponse gtr2 = proxy.getTransfers(TEST_SEED1, 0, 0, true); assertThat(gtr2.getTransfers(), IsNull.notNullValue()); } + + @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); + assertThat(str.getSuccessfully(), IsNull.notNullValue()); + } } \ No newline at end of file From b422b40243c848b40fa83041cb4b9d5ca86802a9 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 31 Dec 2016 10:49:30 +0100 Subject: [PATCH 077/111] extended TrytesConverter test --- src/test/java/jota/TrytesConverterTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/java/jota/TrytesConverterTest.java b/src/test/java/jota/TrytesConverterTest.java index 28b54a6..f6403e5 100644 --- a/src/test/java/jota/TrytesConverterTest.java +++ b/src/test/java/jota/TrytesConverterTest.java @@ -1,12 +1,12 @@ package jota; import jota.utils.TrytesConverter; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.Test; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import org.apache.commons.lang3.RandomStringUtils; - /** * Created by pinpong on 01.12.16. */ @@ -15,19 +15,21 @@ public class TrytesConverterTest { @Test public void shouldConvertStringToTrytes() { assertEquals(TrytesConverter.toTrytes("Z"), "IC"); + assertEquals(TrytesConverter.toTrytes("JOTA JOTA"), "TBYBCCKBEATBYBCCKB"); } + @Test public void shouldConvertTrytesToString() { assertEquals(TrytesConverter.toString("IC"), "Z"); + assertEquals(TrytesConverter.toString("TBYBCCKBEATBYBCCKB"), "JOTA JOTA"); } - + @Test public void shouldConvertBackAndForth() { String str = RandomStringUtils.randomAlphabetic(1000).toUpperCase(); System.err.println(str); String back = TrytesConverter.toString(TrytesConverter.toTrytes(str)); - + assertTrue(str.equals(back)); } - -} +} \ No newline at end of file From d3b45f11edfc6331f609a583b8058af0b3fc41fa Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 1 Jan 2017 19:47:38 +0100 Subject: [PATCH 078/111] added isAddressWithoutChecksum --- src/main/java/jota/utils/Checksum.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/jota/utils/Checksum.java b/src/main/java/jota/utils/Checksum.java index 6bf83f5..6cb46a4 100644 --- a/src/main/java/jota/utils/Checksum.java +++ b/src/main/java/jota/utils/Checksum.java @@ -1,8 +1,7 @@ package jota.utils; -import org.apache.commons.lang3.StringUtils; - import jota.pow.Curl; +import org.apache.commons.lang3.StringUtils; /** * Created by pinpong on 02.12.16. @@ -33,8 +32,12 @@ public class Checksum { return addressWithRecalculateChecksum.equals(addressWithChecksum); } - private static boolean isAddressWithChecksum(String addressWithChecksum) { - return InputValidator.checkAddress(addressWithChecksum) && addressWithChecksum.length() == Constants.ADDRESS_LENGTH_WITH_CHECKSUM; + public static boolean isAddressWithChecksum(String address) { + return InputValidator.checkAddress(address) && address.length() == Constants.ADDRESS_LENGTH_WITH_CHECKSUM; + } + + public static boolean isAddressWithoutChecksum(String address) { + return InputValidator.checkAddress(address) && address.length() == Constants.ADDRESS_LENGTH_WITHOUT_CHECKSUM; } public static String calculateChecksum(String address) { From 01538fe3c4f7b5b2e85b92032e6bda2cc612c6c1 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 1 Jan 2017 20:38:30 +0100 Subject: [PATCH 079/111] fixed sendTransfer --- src/main/java/jota/IotaAPIProxy.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index c18ae60..7e580ae 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -367,8 +367,8 @@ public class IotaAPIProxy { * @param {int} minWeightMagnitude * @return */ - public List sendTrytes(final String[] trytes, final int minWeightMagnitude) { - final GetTransactionsToApproveResponse txs = getTransactionsToApprove(minWeightMagnitude); + public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { + final GetTransactionsToApproveResponse txs = getTransactionsToApprove(depth); // attach to tangle - do pow final GetAttachToTangleResponse res = attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); @@ -798,7 +798,7 @@ public class IotaAPIProxy { bundleTrytes.add(Converter.transactionTrytes(element)); } - return sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), minWeightMagnitude); + return sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), depth, minWeightMagnitude); } /** @@ -821,7 +821,7 @@ public class IotaAPIProxy { public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, final List transfers, Input[] inputs, String address) { List trytes = prepareTransfers(seed, transfers, address, inputs == null ? null : Arrays.asList(inputs)); - List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), minWeightMagnitude); + List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), depth, minWeightMagnitude); return SendTransferResponse.create(trxs.get(0).getPersistence()); } From bf8e7aa122bed296ea6198277889af939d6a5a87 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 1 Jan 2017 21:14:29 +0100 Subject: [PATCH 080/111] added ReplayBundleResponse --- src/main/java/jota/IotaAPIProxy.java | 6 +++-- .../dto/response/ReplayBundleResponse.java | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/main/java/jota/dto/response/ReplayBundleResponse.java diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 7e580ae..c53a885 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -787,7 +787,7 @@ public class IotaAPIProxy { * @method replayBundle * @returns {object} analyzed Transaction objects **/ - public List replayTransfer(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, InvalidSignatureException, ArgumentException { + public ReplayBundleResponse replayBundle(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, InvalidSignatureException, ArgumentException { List bundleTrytes = new ArrayList<>(); @@ -798,7 +798,9 @@ public class IotaAPIProxy { bundleTrytes.add(Converter.transactionTrytes(element)); } - return sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), depth, minWeightMagnitude); + List trxs = sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), depth, minWeightMagnitude); + return ReplayBundleResponse.create(trxs.get(0).getPersistence()); + } /** diff --git a/src/main/java/jota/dto/response/ReplayBundleResponse.java b/src/main/java/jota/dto/response/ReplayBundleResponse.java new file mode 100644 index 0000000..75bad71 --- /dev/null +++ b/src/main/java/jota/dto/response/ReplayBundleResponse.java @@ -0,0 +1,24 @@ +package jota.dto.response; + +/** + * Created by pinpong on 01.01.17. + */ +public class ReplayBundleResponse extends AbstractResponse { + + private Boolean successfully; + + public static ReplayBundleResponse create(Boolean successfully) { + ReplayBundleResponse res = new ReplayBundleResponse(); + res.successfully = successfully; + return res; + } + + public Boolean getSuccessfully() { + return successfully; + } + + public void setSuccessfully(Boolean successfully) { + this.successfully = successfully; + } + +} From 5e4415c3f58e54ca0f87fa7fa27d22729474160b Mon Sep 17 00:00:00 2001 From: pinpong Date: Mon, 2 Jan 2017 17:00:26 +0100 Subject: [PATCH 081/111] fixed test --- src/test/java/jota/IotaAPIProxyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/jota/IotaAPIProxyTest.java b/src/test/java/jota/IotaAPIProxyTest.java index fbfaf8b..f467513 100644 --- a/src/test/java/jota/IotaAPIProxyTest.java +++ b/src/test/java/jota/IotaAPIProxyTest.java @@ -185,7 +185,7 @@ public class IotaAPIProxyTest { @Test public void shouldSendTrytes() { - proxy.sendTrytes(new String[]{TEST_TRYTES}, 18); + proxy.sendTrytes(new String[]{TEST_TRYTES}, 18, 27); } @Test From 04cfb6debce3263966c6ced0afae410518873e9a Mon Sep 17 00:00:00 2001 From: pinpong Date: Mon, 2 Jan 2017 18:07:01 +0100 Subject: [PATCH 082/111] fixed getNewAddress --- src/main/java/jota/IotaAPIProxy.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index c53a885..b3541e8 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -231,7 +231,7 @@ public class IotaAPIProxy { for (int i = index; ; i++) { final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum); - final FindTransactionResponse response = findTransactionsByAddresses(new String[]{newAddress}); + final FindTransactionResponse response = findTransactionsByAddresses(newAddress); allAddresses.add(newAddress); if (response.getHashes().length == 0) { @@ -241,7 +241,9 @@ public class IotaAPIProxy { // If !returnAll return only the last address that was generated if (!returnAll) { - allAddresses = allAddresses.subList(allAddresses.size() - 2, allAddresses.size() - 1); + + //allAddresses = allAddresses.subList(allAddresses.size() - 2, allAddresses.size() - 1); + allAddresses = allAddresses.subList(allAddresses.size() - 1, allAddresses.size()); } return GetNewAddressResponse.create(allAddresses); } From 29c5c26b0aff521f065f66b2f60da0e050896a50 Mon Sep 17 00:00:00 2001 From: pinpong Date: Mon, 2 Jan 2017 21:55:06 +0100 Subject: [PATCH 083/111] sendTransfer return fix --- src/main/java/jota/IotaAPIProxy.java | 26 ++++++++++++++++--- .../dto/response/ReplayBundleResponse.java | 8 +++--- .../dto/response/SendTransferResponse.java | 8 +++--- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index b3541e8..c5f65ad 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -789,7 +789,7 @@ public class IotaAPIProxy { * @method replayBundle * @returns {object} analyzed Transaction objects **/ - public ReplayBundleResponse replayBundle(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, InvalidSignatureException, ArgumentException { + public ReplayBundleResponse replayBundle(String transaction, int depth, int minWeightMagnitude) throws InvalidBundleException, ArgumentException, InvalidSignatureException { List bundleTrytes = new ArrayList<>(); @@ -801,8 +801,18 @@ public class IotaAPIProxy { } List trxs = sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), depth, minWeightMagnitude); - return ReplayBundleResponse.create(trxs.get(0).getPersistence()); + Boolean[] successful = new Boolean[trxs.size()]; + + for (int i = 0; i < trxs.size(); i++) { + + final FindTransactionResponse response = findTransactionsByBundles(trxs.get(i).getBundle()); + + + successful[i] = response.getHashes().length != 0; + } + + return ReplayBundleResponse.create(successful); } /** @@ -826,7 +836,17 @@ public class IotaAPIProxy { List trytes = prepareTransfers(seed, transfers, address, inputs == null ? null : Arrays.asList(inputs)); List trxs = sendTrytes(trytes.toArray(new String[trytes.size()]), depth, minWeightMagnitude); - return SendTransferResponse.create(trxs.get(0).getPersistence()); + + Boolean[] successful = new Boolean[trxs.size()]; + + for (int i = 0; i < trxs.size(); i++) { + + final FindTransactionResponse response = findTransactionsByBundles(trxs.get(i).getBundle()); + + successful[i] = response.getHashes().length != 0; + } + + return SendTransferResponse.create(successful); } /** diff --git a/src/main/java/jota/dto/response/ReplayBundleResponse.java b/src/main/java/jota/dto/response/ReplayBundleResponse.java index 75bad71..f163d33 100644 --- a/src/main/java/jota/dto/response/ReplayBundleResponse.java +++ b/src/main/java/jota/dto/response/ReplayBundleResponse.java @@ -5,19 +5,19 @@ package jota.dto.response; */ public class ReplayBundleResponse extends AbstractResponse { - private Boolean successfully; + private Boolean[] successfully; - public static ReplayBundleResponse create(Boolean successfully) { + public static ReplayBundleResponse create(Boolean[] successfully) { ReplayBundleResponse res = new ReplayBundleResponse(); res.successfully = successfully; return res; } - public Boolean getSuccessfully() { + public Boolean[] getSuccessfully() { return successfully; } - public void setSuccessfully(Boolean successfully) { + public void setSuccessfully(Boolean[] successfully) { this.successfully = successfully; } diff --git a/src/main/java/jota/dto/response/SendTransferResponse.java b/src/main/java/jota/dto/response/SendTransferResponse.java index 4eafeca..62e2a23 100644 --- a/src/main/java/jota/dto/response/SendTransferResponse.java +++ b/src/main/java/jota/dto/response/SendTransferResponse.java @@ -5,19 +5,19 @@ package jota.dto.response; */ public class SendTransferResponse extends AbstractResponse { - private Boolean successfully; + private Boolean[] successfully; - public static SendTransferResponse create(Boolean successfully) { + public static SendTransferResponse create(Boolean[] successfully) { SendTransferResponse res = new SendTransferResponse(); res.successfully = successfully; return res; } - public Boolean getSuccessfully() { + public Boolean[] getSuccessfully() { return successfully; } - public void setSuccessfully(Boolean successfully) { + public void setSuccessfully(Boolean[] successfully) { this.successfully = successfully; } From 8c0833a9ba723d8319140561b6cd7df879f8a319 Mon Sep 17 00:00:00 2001 From: AZ Date: Tue, 3 Jan 2017 10:56:58 +0100 Subject: [PATCH 084/111] ignore errors from getbundle --- src/main/java/jota/IotaAPIProxy.java | 27 ++++++++++++++++----------- src/main/java/jota/utils/Signing.java | 1 - 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index c5f65ad..d550e44 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -314,20 +314,25 @@ public class IotaAPIProxy { if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) return null; } for (String trx : tailTxArray) { - - 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); + 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); + } } + finalBundles.add(gbr); } - finalBundles.add(gbr); + // If error returned from getBundle, simply ignore it because the bundle was most likely incorrect + }catch(Exception e){ + log.warn("GetBundleError: ",e); } + } Collections.sort(finalBundles, new Comparator() { diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index c6110fd..b984a2b 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -163,7 +163,6 @@ public class Signing { digests[i * 243 + j] = digestBuffer[j]; } } - //System.out.println(Arrays.toString(digests).replaceAll("\\s+","")); String address = Converter.trytes(address(digests)); return (expectedAddress.equals(address)); From b730d13105820e959c4da7daa74cd16b404f54d0 Mon Sep 17 00:00:00 2001 From: AZ Date: Tue, 3 Jan 2017 11:03:06 +0100 Subject: [PATCH 085/111] replaced generic exception catch with concrete multicatching of thrown exceptions form getbundle --- src/main/java/jota/IotaAPIProxy.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index d550e44..6963577 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -328,9 +328,9 @@ public class IotaAPIProxy { } finalBundles.add(gbr); } - // If error returned from getBundle, simply ignore it because the bundle was most likely incorrect - }catch(Exception e){ - log.warn("GetBundleError: ",e); + // If error returned from getBundle, simply ignore it because the bundle was most likely incorrect + } catch (InvalidBundleException | ArgumentException | InvalidSignatureException e) { + log.warn("GetBundleError: ", e); } } From 3cb9edfc1359aab8712542408900c0ea38dfde3a Mon Sep 17 00:00:00 2001 From: AZ Date: Tue, 3 Jan 2017 11:49:07 +0100 Subject: [PATCH 086/111] added surefire plugin to pom to skip tests if needed --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 70b381e..d3b98e8 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,13 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + true + + From b9b3b5d82852d82797ddc77b65d3ce2fb75b7831 Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 6 Jan 2017 15:06:11 +0100 Subject: [PATCH 087/111] validate seed & if needed pad to 81 chars --- node_config.properties | 6 ++-- src/main/java/jota/IotaAPIProxy.java | 37 +++++++++++++++++--- src/main/java/jota/utils/InputValidator.java | 28 +++++++++------ 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/node_config.properties b/node_config.properties index e5e5a5a..fd80f02 100644 --- a/node_config.properties +++ b/node_config.properties @@ -1,5 +1,7 @@ iota.node.protocol=http -#iota.node.host=138.68.126.141 -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.port=14265 diff --git a/src/main/java/jota/IotaAPIProxy.java b/src/main/java/jota/IotaAPIProxy.java index 6963577..b1b6ad8 100644 --- a/src/main/java/jota/IotaAPIProxy.java +++ b/src/main/java/jota/IotaAPIProxy.java @@ -13,6 +13,7 @@ import jota.utils.IotaAPIUtils; import jota.utils.Signing; import okhttp3.OkHttpClient; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import retrofit2.Call; @@ -259,6 +260,11 @@ public class IotaAPIProxy { * @returns {object} success **/ public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + // validate & if needed pad seed + if ( (seed = InputValidator.validateSeed(seed)) == null) { + throw new IllegalStateException("Invalid Seed"); + } + start = start != null ? 0 : start; end = end == null ? null : end; inclusionStates = inclusionStates != null ? inclusionStates : null; @@ -266,12 +272,19 @@ public class IotaAPIProxy { if (start > end || end > (start + 500)) { 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"); 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); } + sw.stop(); return null; } @@ -310,7 +323,11 @@ public class IotaAPIProxy { // of the tail transactions, and thus the bundles GetInclusionStateResponse gisr = null; if (inclusionStates) { - gisr = getLatestInclusion(tailTxArray); + try { + gisr = getLatestInclusion(tailTxArray); + } catch (IllegalAccessError e) { + + } if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) return null; } for (String trx : tailTxArray) { @@ -473,13 +490,19 @@ public class IotaAPIProxy { * @property {string} address Remainder address * @returns {array} trytes Returns bundle trytes **/ - public List prepareTransfers(final String seed, final List transfers, String remainder, List inputs) { + public List prepareTransfers(String seed, final List transfers, String remainder, List inputs) { // Input validation of transfers object if (!InputValidator.isTransfersCollectionCorrect(transfers)) { throw new IllegalStateException("Invalid Transfer"); } + // validate & if needed pad seed + if ( (seed = InputValidator.validateSeed(seed)) == null) { + throw new IllegalStateException("Invalid Seed"); + } + + // Create a new bundle final Bundle bundle = new Bundle(); final List signatureFragments = new ArrayList<>(); @@ -619,13 +642,18 @@ public class IotaAPIProxy { * @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) { + public GetBalancesAndFormatResponse getInputs(String seed, final List balances, int start, int end, int threshold) { // validate the seed if (!InputValidator.isTrytes(seed, 0)) { throw new IllegalStateException("Invalid Seed"); } + // validate & if needed pad seed + if ( (seed = InputValidator.validateSeed(seed)) == null) { + throw new IllegalStateException("Invalid Seed"); + } + // If start value bigger than end, return error // or if difference between end and start is bigger than 500 keys if (start > end || end > (start + 500)) { @@ -913,6 +941,7 @@ public class IotaAPIProxy { final long totalValue, final String remainderAddress, final List signatureFragments) { + for (int i = 0; i < inputs.size(); i++) { long thisBalance = inputs.get(i).getBalance(); long totalTransferValue = totalValue; diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 90392e7..b636bb5 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -28,7 +28,7 @@ public class InputValidator { public static boolean isTrytes(final String trytes, final int length) { return trytes.matches("^[A-Z9]{" + (length == 0 ? "0," : length) + "}$"); } - + public static boolean isValue(final String value) { return NumberUtils.isNumber(value); } @@ -51,16 +51,16 @@ public class InputValidator { } return true; } - + /** - * checks if input is correct hash collections - * - * @method isTransfersArray - * @param {array} hash - * @returns {boolean} - **/ + * checks if input is correct hash collections + * + * @param {array} hash + * @method isTransfersArray + * @returns {boolean} + **/ public static boolean isTransfersCollectionCorrect(final List transfers) { - + for (final Transfer transfer : transfers) { if (!isTransfersArray(transfer)) { return false; @@ -68,9 +68,9 @@ public class InputValidator { } return true; } - + public static boolean isTransfersArray(final Transfer transfer) { - + if (!isAddress(transfer.getAddress())) { return false; } @@ -87,4 +87,10 @@ public class InputValidator { return true; } + + public static String validateSeed(String seed) { + if (seed.length() > 81) return null; + while (seed.length() < 81) seed += 9; + return seed; + } } From 034c45e28af66d56c9a4d68abb8bcfe453d15f66 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 8 Jan 2017 19:06:17 +0100 Subject: [PATCH 088/111] extended IotaUnitConverter --- src/main/java/jota/utils/IotaUnitConverter.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/jota/utils/IotaUnitConverter.java b/src/main/java/jota/utils/IotaUnitConverter.java index d25a39e..eac11b4 100644 --- a/src/main/java/jota/utils/IotaUnitConverter.java +++ b/src/main/java/jota/utils/IotaUnitConverter.java @@ -16,24 +16,28 @@ public class IotaUnitConverter { return (long) (amount / Math.pow(10, toUnit.getValue())); } - public static String convertRawIotaAmountToDisplayText(long amount) { + public static String convertRawIotaAmountToDisplayText(long amount, boolean extended) { IotaUnits unit = findOptimalIotaUnitToDisplay(amount); double amountInDisplayUnit = convertAmountTo(amount, unit); - return createAmountWithUnitDisplayText(amountInDisplayUnit, unit); + return createAmountWithUnitDisplayText(amountInDisplayUnit, unit, extended); } public static double convertAmountTo(long amount, IotaUnits target) { return amount / Math.pow(10, target.getValue()); } - private static String createAmountWithUnitDisplayText(double amountInUnit, IotaUnits unit) { - String result = createAmountDisplayText(amountInUnit, unit); + private static String createAmountWithUnitDisplayText(double amountInUnit, IotaUnits unit, boolean extended) { + String result = createAmountDisplayText(amountInUnit, unit, extended); result += " " + unit.getUnit(); return result; } - public static String createAmountDisplayText(double amountInUnit, IotaUnits unit) { - DecimalFormat df = new DecimalFormat("##0.##################"); + public static String createAmountDisplayText(double amountInUnit, IotaUnits unit, boolean extended) { + DecimalFormat df; + if (extended) df = new DecimalFormat("##0.##################"); + else + df = new DecimalFormat("##0.##"); + String result = ""; // display unit as integer if value is between 1-999 or in decimal format result += unit == IotaUnits.IOTA ? (long) amountInUnit : df.format(amountInUnit); From deae4945b40535bd69c7f8a42cb785702320fad2 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 15 Jan 2017 18:04:45 +0100 Subject: [PATCH 089/111] * refactoring started * performance optimization through multithreading * added duration for the proposed calls --- node_config.properties | 4 +- pom.xml | 5 + .../jota/{IotaAPIProxy.java => IotaAPI.java} | 418 +++++------------- src/main/java/jota/IotaAPICoreProxy.java | 260 +++++++++++ .../jota/dto/response/AbstractResponse.java | 8 +- .../response/GetAttachToTangleResponse.java | 4 + .../GetBalancesAndFormatResponse.java | 9 +- .../jota/dto/response/GetBundleResponse.java | 3 +- .../dto/response/GetNewAddressResponse.java | 3 +- .../dto/response/GetTransferResponse.java | 2 +- .../dto/response/ReplayBundleResponse.java | 3 +- .../dto/response/SendTransferResponse.java | 3 +- .../response/StoreTransactionsResponse.java | 4 +- src/main/java/jota/model/Bundle.java | 18 +- src/main/java/jota/pow/ICurl.java | 15 + .../java/jota/pow/{Curl.java => JCurl.java} | 24 +- src/main/java/jota/utils/Checksum.java | 4 +- src/main/java/jota/utils/Converter.java | 8 +- src/main/java/jota/utils/IotaAPIUtils.java | 2 - .../java/jota/utils/NamedThreadFactory.java | 26 ++ src/main/java/jota/utils/Parallel.java | 45 ++ src/main/java/jota/utils/Signing.java | 46 +- src/main/java/jota/utils/StopWatch.java | 71 +++ ...IotaAPIProxyTest.java => IotaAPITest.java} | 186 +++----- src/test/java/jota/IotaCoreApiTest.java | 132 ++++++ src/test/java/jota/IotaUnitConverterTest.java | 12 +- 26 files changed, 803 insertions(+), 512 deletions(-) rename src/main/java/jota/{IotaAPIProxy.java => IotaAPI.java} (68%) create mode 100644 src/main/java/jota/IotaAPICoreProxy.java create mode 100644 src/main/java/jota/pow/ICurl.java rename src/main/java/jota/pow/{Curl.java => JCurl.java} (78%) create mode 100644 src/main/java/jota/utils/NamedThreadFactory.java create mode 100644 src/main/java/jota/utils/Parallel.java create mode 100644 src/main/java/jota/utils/StopWatch.java rename src/test/java/jota/{IotaAPIProxyTest.java => IotaAPITest.java} (50%) create mode 100644 src/test/java/jota/IotaCoreApiTest.java 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"); } } From 327c3bbf72ca3c696c59509428837d92f54eea61 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 15 Jan 2017 18:46:13 +0100 Subject: [PATCH 090/111] allow the injection of custom curl implementations --- src/main/java/jota/IotaAPI.java | 25 ++++--- src/main/java/jota/model/Bundle.java | 5 +- src/main/java/jota/model/Transaction.java | 1 + src/main/java/jota/utils/Converter.java | 42 ----------- src/main/java/jota/utils/IotaAPIUtils.java | 21 +++--- src/main/java/jota/utils/Signing.java | 49 ++++++------- .../java/jota/utils/TransactionConverter.java | 69 +++++++++++++++++++ src/test/java/jota/IotaAPITest.java | 4 +- 8 files changed, 124 insertions(+), 92 deletions(-) create mode 100644 src/main/java/jota/utils/TransactionConverter.java diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 717f277..2bc36f8 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -10,7 +10,6 @@ import jota.pow.JCurl; import jota.utils.*; import jota.utils.StopWatch; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,7 +68,7 @@ public class IotaAPI { // and return the list of all addresses if (total != 0) { for (int i = index; i < index + total; i++) { - allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum)); + allAddresses.add(IotaAPIUtils.newAddress(seed, i, checksum, customCurl)); } return GetNewAddressResponse.create(allAddresses, stopWatch.getElapsedTimeMili()); } @@ -77,7 +76,7 @@ public class IotaAPI { // 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, customCurl); final FindTransactionResponse response = coreProxy.findTransactionsByAddresses(newAddress); allAddresses.add(newAddress); @@ -247,7 +246,7 @@ public class IotaAPI { final List trx = new ArrayList<>(); for (final String tx : Arrays.asList(res.getTrytes())) { - trx.add(Converter.transactionObject(tx)); + trx.add(new TransactionConverter(customCurl).transactionObject(tx)); } return trx; } @@ -273,7 +272,7 @@ public class IotaAPI { final List trxs = new ArrayList<>(); for (final String tryte : trytesResponse.getTrytes()) { - trxs.add(Converter.transactionObject(tryte)); + trxs.add(new TransactionConverter(customCurl).transactionObject(tryte)); } return trxs; } @@ -456,7 +455,7 @@ public class IotaAPI { } else { // If no input required, don't sign and simply finalize the bundle - bundle.finalize(); + bundle.finalize(customCurl); bundle.addTrytes(signatureFragments); List trxb = bundle.getTransactions(); @@ -509,7 +508,7 @@ public class IotaAPI { for (int i = start; i < end; i++) { - String address = IotaAPIUtils.newAddress(seed, i, false); + String address = IotaAPIUtils.newAddress(seed, i, false, customCurl); allAddresses.add(address); } @@ -644,7 +643,7 @@ public class IotaAPI { for (int i = 0; i < signaturesToValidate.size(); i++) { String[] signatureFragments = signaturesToValidate.get(i).getSignatureFragments().toArray(new String[signaturesToValidate.get(i).getSignatureFragments().size()]); String address = signaturesToValidate.get(i).getAddress(); - boolean isValidSignature = Signing.validateSignatures(address, signatureFragments, bundleHash); + boolean isValidSignature = new Signing().validateSignatures(address, signatureFragments, bundleHash); if (!isValidSignature) throw new InvalidSignatureException(); } @@ -744,7 +743,7 @@ public class IotaAPI { throw new ArgumentException("Bundle transactions not visible"); } - Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]); + Transaction trx = new TransactionConverter(customCurl).transactionObject(gtr.getTrytes()[0]); if (trx == null || trx.getBundle() == null) { throw new ArgumentException("Invalid trytes, could not create object"); } @@ -785,7 +784,7 @@ public class IotaAPI { throw new ArgumentException("Bundle transactions not visible"); } - Transaction trx = Converter.transactionObject(gtr.getTrytes()[0]); + Transaction trx = new TransactionConverter(customCurl).transactionObject(gtr.getTrytes()[0]); if (trx == null || trx.getBundle() == null) { throw new ArgumentException("Invalid trytes, could not create object"); } @@ -821,7 +820,7 @@ public class IotaAPI { // Remainder bundle entry bundle.addEntry(1, remainderAddress, remainder, tag, timestamp); // Final function for signing inputs - return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments, customCurl); } else if (remainder > 0) { // Generate a new Address by calling getNewAddress @@ -830,11 +829,11 @@ public class IotaAPI { bundle.addEntry(1, res.getAddresses().get(0), remainder, tag, timestamp); // Final function for signing inputs - return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments, customCurl); } else { // If there is no remainder, do not add transaction to bundle // simply sign and return - return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments); + return IotaAPIUtils.signInputsAndReturn(seed, inputs, bundle, signatureFragments, customCurl); } // If multiple inputs provided, subtract the totalTransferValue by diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index ad8ef4d..e445627 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -1,5 +1,6 @@ package jota.model; +import jota.pow.ICurl; import jota.pow.JCurl; import jota.utils.Converter; @@ -54,9 +55,9 @@ public class Bundle implements Comparable { } } - public void finalize() { + public void finalize(ICurl customCurl) { - JCurl curl = new JCurl(); + ICurl curl = customCurl == null ? new JCurl() : customCurl; curl.reset(); for (int i = 0; i < this.getTransactions().size(); i++) { diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index 210a287..f6b38dc 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -165,4 +165,5 @@ public class Transaction { if (((Transaction) obj).getHash().equals(this.getHash())) return true; return false; } + } \ No newline at end of file diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 8872481..5f2d97c 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -246,46 +246,4 @@ public class Converter { + trx.getNonce(); } - public static Transaction transactionObject(final String trytes) { - - if (StringUtils.isEmpty(trytes)) { - log.warn("Warning: empty trytes in input for transactionObject"); - return null; - } - - // validity check - for (int i = 2279; i < 2295; i++) { - if (trytes.charAt(i) != '9') { - log.warn("Trytes {} does not seem a valid tryte", trytes); - return null; - } - } - - int[] transactionTrits = Converter.trits(trytes); - int[] hash = new int[243]; - - final JCurl curl = new JCurl(); // we need a fluent JCurl. - - // generate the correct transaction hash - curl.reset(); - curl.absorbb(transactionTrits, 0, transactionTrits.length); - curl.squeezee(hash, 0, hash.length); - - Transaction trx = new Transaction(); - - trx.setHash(Converter.trytes(hash)); - trx.setSignatureFragments(trytes.substring(0, 2187)); - trx.setAddress(trytes.substring(2187, 2268)); - trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837))); - trx.setTag(trytes.substring(2295, 2322)); - trx.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993))); - trx.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020))); - trx.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047))); - trx.setBundle(trytes.substring(2349, 2430)); - trx.setTrunkTransaction(trytes.substring(2430, 2511)); - trx.setBranchTransaction(trytes.substring(2511, 2592)); - trx.setNonce(trytes.substring(2592, 2673)); - - return trx; - } } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 6430b0d..2a93482 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -2,6 +2,7 @@ package jota.utils; import java.util.*; +import jota.pow.ICurl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,11 +27,11 @@ public class IotaAPIUtils { * @param checksum * @return an String with address */ - public static String newAddress(String seed, int index, boolean checksum) { - - final int[] key = Signing.key(Converter.trits(seed), index, 2); - final int[] digests = Signing.digests(key); - final int[] addressTrits = Signing.address(digests); + public static String newAddress(String seed, int index, boolean checksum, ICurl curl) { + Signing signing = new Signing(curl); + final int[] key = signing.key(Converter.trits(seed), index, 2); + final int[] digests = signing.digests(key); + final int[] addressTrits = signing.address(digests); String address = Converter.trytes(addressTrits); @@ -43,8 +44,8 @@ public class IotaAPIUtils { public static List signInputsAndReturn(final String seed, final List inputs, final Bundle bundle, - final List signatureFragments) { - bundle.finalize(); + final List signatureFragments, ICurl curl) { + bundle.finalize(curl); bundle.addTrytes(signatureFragments); // SIGNING OF INPUTS @@ -68,7 +69,7 @@ public class IotaAPIUtils { String bundleHash = bundle.getTransactions().get(i).getBundle(); // Get corresponding private key of address - int[] key = Signing.key(Converter.trits(seed), keyIndex, 2); + int[] key = new Signing(curl).key(Converter.trits(seed), keyIndex, 2); // First 6561 trits for the firstFragment int[] firstFragment = Arrays.copyOfRange(key, 0, 6561); @@ -80,7 +81,7 @@ public class IotaAPIUtils { int[] firstBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 0, 27); // Calculate the new signatureFragment with the first bundle fragment - int[] firstSignedFragment = Signing.signatureFragment(firstBundleFragment, firstFragment); + int[] firstSignedFragment = new Signing(curl).signatureFragment(firstBundleFragment, firstFragment); // Convert signature to trytes and assign the new signatureFragment bundle.getTransactions().get(i).setSignatureFragments(Converter.trytes(firstSignedFragment)); @@ -97,7 +98,7 @@ public class IotaAPIUtils { int[] secondBundleFragment = Arrays.copyOfRange(normalizedBundleHash, 27, 27 * 2); // Calculate the new signature - int[] secondSignedFragment = Signing.signatureFragment(secondBundleFragment, secondFragment); + int[] secondSignedFragment = new Signing(curl).signatureFragment(secondBundleFragment, secondFragment); // Convert signature to trytes and assign it again to this bundle entry bundle.getTransactions().get(j).setSignatureFragments(Converter.trytes(secondSignedFragment)); diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index 9e48239..728271e 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -5,11 +5,21 @@ import java.util.Arrays; import java.util.List; import jota.model.Bundle; +import jota.pow.ICurl; import jota.pow.JCurl; public class Signing { + private ICurl curl; - static int[] key(int[] seed, int index, int length) { + public Signing() { + this(null); + } + + public Signing(ICurl curl) { + this.curl = curl == null ? new JCurl() : curl; + } + + public int[] key(int[] seed, int index, int length) { for (int i = 0; i < index; i++) { for (int j = 0; j < 243; j++) { @@ -21,7 +31,6 @@ public class Signing { } } - final JCurl curl = new JCurl(); curl.reset(); curl.absorbb(seed, 0, seed.length); curl.squeezee(seed, 0, seed.length); @@ -44,7 +53,7 @@ public class Signing { return to(key); } - private static int[] to(List key) { + private int[] to(List key) { int a[] = new int[key.size()]; int i = 0; for (Integer v : key) { @@ -53,21 +62,19 @@ public class Signing { return a; } - public static int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) { + public int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) { int[] signatureFragment = keyFragment; int[] hash; - JCurl curl = new JCurl(); - for (int i = 0; i < 27; i++) { hash = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243); for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) { curl.reset() - .absorbb(hash, 0, hash.length) - .squeezee(hash, 0, hash.length); + .absorbb(hash, 0, hash.length) + .squeezee(hash, 0, hash.length); } for (int j = 0; j < 243; j++) { @@ -78,17 +85,15 @@ public class Signing { return signatureFragment; } - public static int[] address(int[] digests) { - final JCurl curl = new JCurl(); + public int[] address(int[] digests) { int[] address = new int[243]; curl.reset() - .absorbb(digests) - .squeezee(address); + .absorbb(digests) + .squeezee(address); return address; } - - public static int[] digests(int[] key) { - final JCurl curl = new JCurl(); + + public int[] digests(int[] key) { int[] digests = new int[(int) Math.floor(key.length / 6561) * 243]; int[] buffer = new int[243]; @@ -101,8 +106,8 @@ public class Signing { buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); for (int k = 0; k < 26; k++) { curl.reset() - .absorbb(buffer) - .squeezee(buffer); + .absorbb(buffer) + .squeezee(buffer); } System.arraycopy(buffer, 0, keyFragment, j * 243, 243); } @@ -116,18 +121,16 @@ public class Signing { return digests; } - public static int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) { - + public int[] digest(int[] normalizedBundleFragment, int[] signatureFragment) { + curl.reset(); int[] buffer = new int[243]; - 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; ) { - JCurl jCurl = new JCurl(); + ICurl jCurl = new JCurl(); jCurl.reset(); jCurl.absorbb(buffer); jCurl.squeezee(buffer); @@ -139,7 +142,7 @@ public class Signing { return buffer; } - public static Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) { + public Boolean validateSignatures(String expectedAddress, String[] signatureFragments, String bundleHash) { Bundle bundle = new Bundle(); diff --git a/src/main/java/jota/utils/TransactionConverter.java b/src/main/java/jota/utils/TransactionConverter.java new file mode 100644 index 0000000..0949072 --- /dev/null +++ b/src/main/java/jota/utils/TransactionConverter.java @@ -0,0 +1,69 @@ +package jota.utils; + +import jota.model.Transaction; +import jota.pow.ICurl; +import jota.pow.JCurl; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; + +/** + * Created by Adrian on 15.01.2017. + */ +public class TransactionConverter { + private static final Logger log = LoggerFactory.getLogger(TransactionConverter.class); + private ICurl customCurl; + + public TransactionConverter(ICurl curl) { + customCurl = curl; + } + + public TransactionConverter() { + customCurl = null; + } + + public Transaction transactionObject(final String trytes) { + + if (StringUtils.isEmpty(trytes)) { + log.warn("Warning: empty trytes in input for transactionObject"); + return null; + } + + // validity check + for (int i = 2279; i < 2295; i++) { + if (trytes.charAt(i) != '9') { + log.warn("Trytes {} does not seem a valid tryte", trytes); + return null; + } + } + + int[] transactionTrits = Converter.trits(trytes); + int[] hash = new int[243]; + + final JCurl curl = new JCurl(); // we need a fluent JCurl. + + // generate the correct transaction hash + curl.reset(); + curl.absorbb(transactionTrits, 0, transactionTrits.length); + curl.squeezee(hash, 0, hash.length); + + Transaction trx = new Transaction(); + + trx.setHash(Converter.trytes(hash)); + trx.setSignatureFragments(trytes.substring(0, 2187)); + trx.setAddress(trytes.substring(2187, 2268)); + trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837))); + trx.setTag(trytes.substring(2295, 2322)); + trx.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993))); + trx.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020))); + trx.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047))); + trx.setBundle(trytes.substring(2349, 2430)); + trx.setTrunkTransaction(trytes.substring(2430, 2511)); + trx.setBranchTransaction(trytes.substring(2511, 2592)); + trx.setNonce(trytes.substring(2592, 2673)); + + return trx; + } +} diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index 1a20fbf..f66eb70 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -132,7 +132,7 @@ public class IotaAPITest { } } } - +/* @Test public void shouldSendTrytes() { iotaClient.sendTrytes(new String[]{TEST_TRYTES}, 9, 18); @@ -145,5 +145,5 @@ public class IotaAPITest { SendTransferResponse str = iotaClient.sendTransfer(TEST_SEED2, 9, 18, transfers, null, null); assertThat(str.getSuccessfully(), IsNull.notNullValue()); } - +*/ } \ No newline at end of file From a27168dee028227839e18edefe26ed8dbaebba4e Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 15 Jan 2017 20:45:46 +0100 Subject: [PATCH 091/111] cleanup --- pom.xml | 5 -- src/main/java/jota/IotaAPI.java | 76 ++++++++++--------- src/main/java/jota/IotaAPICoreProxy.java | 19 ++--- .../request/IotaAttachToTangleRequest.java | 32 ++++++++ .../IotaBroadcastTransactionRequest.java | 8 ++ .../request/IotaFindTransactionsRequest.java | 32 ++++++++ .../dto/request/IotaGetBalancesRequest.java | 15 ++++ .../request/IotaGetInclusionStateRequest.java | 15 ++++ .../IotaGetTransactionsToApproveRequest.java | 8 ++ .../dto/request/IotaGetTrytesRequest.java | 8 ++ .../dto/request/IotaNeighborsRequest.java | 8 ++ .../request/IotaStoreTransactionsRequest.java | 8 ++ .../response/AnalyzeTransactionResponse.java | 2 +- src/main/java/jota/model/Transaction.java | 6 +- src/main/java/jota/pow/ICurl.java | 25 +++--- src/main/java/jota/utils/Converter.java | 4 +- src/main/java/jota/utils/InputValidator.java | 9 +-- src/main/java/jota/utils/IotaAPIUtils.java | 8 +- src/main/java/jota/utils/IotaUnits.java | 4 - src/main/java/jota/utils/Parallel.java | 6 +- src/main/java/jota/utils/Signing.java | 10 +-- src/test/java/jota/IotaAPITest.java | 4 +- 22 files changed, 217 insertions(+), 95 deletions(-) diff --git a/pom.xml b/pom.xml index 3be12e9..d3b98e8 100644 --- a/pom.xml +++ b/pom.xml @@ -63,11 +63,6 @@ 4.12 test - - net.java.dev.jna - jna-platform - 4.0.0 - diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 2bc36f8..13ea298 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -8,7 +8,6 @@ import jota.model.*; import jota.pow.ICurl; import jota.pow.JCurl; import jota.utils.*; -import jota.utils.StopWatch; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,26 +27,17 @@ import java.util.*; * * @author davassi */ -public class IotaAPI { +public class IotaAPI extends IotaAPICoreProxy { private static final Logger log = LoggerFactory.getLogger(IotaAPI.class); - private IotaAPICoreProxy coreProxy; private ICurl customCurl; private StopWatch stopWatch; - public IotaAPI() { - this(null); + protected IotaAPI(Builder builder) { + super(builder); + customCurl = builder.customCurl; } - public IotaAPI(ICurl customCurl) { - this.customCurl = customCurl; - coreProxy = new IotaAPICoreProxy.Builder().build(); - stopWatch = new StopWatch(); - } - - - // end of proxied calls. - /** * Generates a new address from a seed and returns the remainderAddress. * This is either done deterministically, or by providing the index of the new remainderAddress @@ -77,7 +67,7 @@ public class IotaAPI { for (int i = index; ; i++) { final String newAddress = IotaAPIUtils.newAddress(seed, i, checksum, customCurl); - final FindTransactionResponse response = coreProxy.findTransactionsByAddresses(newAddress); + final FindTransactionResponse response = findTransactionsByAddresses(newAddress); allAddresses.add(newAddress); if (response.getHashes().length == 0) { @@ -168,7 +158,7 @@ public class IotaAPI { if (inclusionStates) { try { gisr = getLatestInclusion(tailTxArray); - } catch (IllegalAccessError e) { + } catch (IllegalAccessError ignored) { } if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) @@ -213,12 +203,12 @@ public class IotaAPI { public StoreTransactionsResponse broadcastAndStore(final String... trytes) { try { - coreProxy.broadcastTransactions(trytes); + broadcastTransactions(trytes); } catch (Exception e) { log.error("Impossible to broadcastAndStore, aborting.", e); throw new IllegalStateException("BroadcastAndStore Illegal state Exception"); } - return coreProxy.storeTransactions(trytes); + return storeTransactions(trytes); } /** @@ -230,10 +220,10 @@ public class IotaAPI { * @return */ public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { - final GetTransactionsToApproveResponse txs = coreProxy.getTransactionsToApprove(depth); + final GetTransactionsToApproveResponse txs = getTransactionsToApprove(depth); // attach to tangle - do pow - final GetAttachToTangleResponse res = coreProxy.attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); + final GetAttachToTangleResponse res = attachToTangle(txs.getTrunkTransaction(), txs.getBranchTransaction(), minWeightMagnitude, trytes); try { broadcastAndStore(res.getTrytes()); @@ -267,7 +257,7 @@ public class IotaAPI { throw new IllegalStateException("Not an Array of Hashes: " + Arrays.toString(hashes)); } - final GetTrytesResponse trytesResponse = coreProxy.getTrytes(hashes); + final GetTrytesResponse trytesResponse = getTrytes(hashes); final List trxs = new ArrayList<>(); @@ -288,7 +278,7 @@ public class IotaAPI { * @returns {object} success **/ public List findTransactionObjects(String[] input) { - FindTransactionResponse ftr = coreProxy.findTransactions(input, null, null, null); + FindTransactionResponse ftr = findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) return null; @@ -307,7 +297,7 @@ public class IotaAPI { * @returns {object} success **/ public List findTransactionObjectsByBundle(String[] input) { - FindTransactionResponse ftr = coreProxy.findTransactions(null, null, null, input); + FindTransactionResponse ftr = findTransactions(null, null, null, input); if (ftr == null || ftr.getHashes() == null) return null; @@ -416,7 +406,7 @@ public class IotaAPI { inputsAddresses.add(i.getAddress()); } - GetBalancesResponse balancesResponse = coreProxy.getBalances(100, inputsAddresses); + GetBalancesResponse balancesResponse = getBalances(100, inputsAddresses); String[] balances = balancesResponse.getBalances(); List confirmedInputs = new ArrayList<>(); @@ -448,7 +438,7 @@ public class IotaAPI { // confirm that the inputs exceed the threshold else { - GetBalancesAndFormatResponse newinputs = getInputs(seed, Collections.EMPTY_LIST, 0, 0, totalValue); + @SuppressWarnings("unchecked") GetBalancesAndFormatResponse newinputs = getInputs(seed, Collections.EMPTY_LIST, 0, 0, totalValue); // If inputs with enough balance return addRemainder(seed, newinputs.getInput(), bundle, tag, totalValue, null, signatureFragments); } @@ -530,13 +520,13 @@ public class IotaAPI { public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, List balances, long threshold, int start, int end, StopWatch stopWatch) { if (balances == null || balances.isEmpty()) { - GetBalancesResponse getBalancesResponse = coreProxy.getBalances(100, addresses); + GetBalancesResponse getBalancesResponse = getBalances(100, addresses); balances = Arrays.asList(getBalancesResponse.getBalances()); } // If threshold defined, keep track of whether reached or not // else set default to true - boolean thresholdReached = threshold != 0 ? false : true; + boolean thresholdReached = threshold == 0; int i = -1; List inputs = new ArrayList<>(); @@ -640,9 +630,9 @@ public class IotaAPI { throw new InvalidBundleException("Invalid Bundle"); // Validate the signatures - for (int i = 0; i < signaturesToValidate.size(); i++) { - String[] signatureFragments = signaturesToValidate.get(i).getSignatureFragments().toArray(new String[signaturesToValidate.get(i).getSignatureFragments().size()]); - String address = signaturesToValidate.get(i).getAddress(); + for (Signature aSignaturesToValidate : signaturesToValidate) { + String[] signatureFragments = aSignaturesToValidate.getSignatureFragments().toArray(new String[aSignaturesToValidate.getSignatureFragments().size()]); + String address = aSignaturesToValidate.getAddress(); boolean isValidSignature = new Signing().validateSignatures(address, signatureFragments, bundleHash); if (!isValidSignature) throw new InvalidSignatureException(); @@ -679,7 +669,7 @@ public class IotaAPI { for (int i = 0; i < trxs.size(); i++) { - final FindTransactionResponse response = coreProxy.findTransactionsByBundles(trxs.get(i).getBundle()); + final FindTransactionResponse response = findTransactionsByBundles(trxs.get(i).getBundle()); successful[i] = response.getHashes().length != 0; @@ -697,12 +687,12 @@ public class IotaAPI { * @returns {array} state **/ public GetInclusionStateResponse getLatestInclusion(String[] hashes) { - GetNodeInfoResponse getNodeInfoResponse = coreProxy.getNodeInfo(); + GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); if (getNodeInfoResponse == null) return null; String[] latestMilestone = {getNodeInfoResponse.getLatestSolidSubtangleMilestone()}; - return coreProxy.getInclusionStates(hashes, latestMilestone); + return getInclusionStates(hashes, latestMilestone); } public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, final List transfers, Input[] inputs, String address) { @@ -715,7 +705,7 @@ public class IotaAPI { for (int i = 0; i < trxs.size(); i++) { - final FindTransactionResponse response = coreProxy.findTransactionsByBundles(trxs.get(i).getBundle()); + final FindTransactionResponse response = findTransactionsByBundles(trxs.get(i).getBundle()); successful[i] = response.getHashes().length != 0; } @@ -735,7 +725,7 @@ public class IotaAPI { * @returns {array} bundle Transaction objects **/ public Bundle traverseBundle(String trunkTx, String bundleHash, Bundle bundle) throws ArgumentException { - GetTrytesResponse gtr = coreProxy.getTrytes(trunkTx); + GetTrytesResponse gtr = getTrytes(trunkTx); if (gtr != null) { @@ -776,7 +766,7 @@ public class IotaAPI { } public String findTailTransactionHash(String hash) throws ArgumentException { - GetTrytesResponse gtr = coreProxy.getTrytes(hash); + GetTrytesResponse gtr = getTrytes(hash); if (gtr == null) throw new ArgumentException("Invalid hash"); @@ -844,4 +834,18 @@ public class IotaAPI { } return null; } + + public static class Builder extends IotaAPICoreProxy.Builder { + private ICurl customCurl; + + public Builder withCustomCurl(ICurl curl) { + customCurl = curl; + return this; + } + + public IotaAPI build() { + super.build(); + return new IotaAPI(this); + } + } } diff --git a/src/main/java/jota/IotaAPICoreProxy.java b/src/main/java/jota/IotaAPICoreProxy.java index 2be14bd..e87e052 100644 --- a/src/main/java/jota/IotaAPICoreProxy.java +++ b/src/main/java/jota/IotaAPICoreProxy.java @@ -28,7 +28,7 @@ public class IotaAPICoreProxy { private IotaAPIService service; private String protocol, host, port; - private IotaAPICoreProxy(final Builder builder) { + protected IotaAPICoreProxy(final Builder builder) { protocol = builder.protocol; host = builder.host; port = builder.port; @@ -52,7 +52,7 @@ public class IotaAPICoreProxy { } } - private static final String env(String env, String def) { + private static 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. " @@ -187,7 +187,8 @@ public class IotaAPICoreProxy { return wrapCheckedException(res).body(); } - public static class Builder { + @SuppressWarnings("unchecked") + public static class Builder > { String protocol, host, port; @@ -241,19 +242,19 @@ public class IotaAPICoreProxy { port = env("IOTA_NODE_PORT", "14265"); } - public Builder host(String host) { + public T host(String host) { this.host = host; - return this; + return (T) this; } - public Builder port(String port) { + public T port(String port) { this.port = port; - return this; + return (T) this; } - public Builder protocol(String protocol) { + public T protocol(String protocol) { this.protocol = protocol; - return this; + return (T) this; } } diff --git a/src/main/java/jota/dto/request/IotaAttachToTangleRequest.java b/src/main/java/jota/dto/request/IotaAttachToTangleRequest.java index bfef85b..8d50a54 100644 --- a/src/main/java/jota/dto/request/IotaAttachToTangleRequest.java +++ b/src/main/java/jota/dto/request/IotaAttachToTangleRequest.java @@ -20,4 +20,36 @@ public class IotaAttachToTangleRequest extends IotaCommandRequest { public static IotaAttachToTangleRequest createAttachToTangleRequest(final String trunkTransaction, final String branchTransaction, final Integer minWeightMagnitude, final String... trytes) { return new IotaAttachToTangleRequest(trunkTransaction, branchTransaction, minWeightMagnitude, trytes); } + + public String getTrunkTransaction() { + return trunkTransaction; + } + + public void setTrunkTransaction(String trunkTransaction) { + this.trunkTransaction = trunkTransaction; + } + + public String getBranchTransaction() { + return branchTransaction; + } + + public void setBranchTransaction(String branchTransaction) { + this.branchTransaction = branchTransaction; + } + + public Integer getMinWeightMagnitude() { + return minWeightMagnitude; + } + + public void setMinWeightMagnitude(Integer minWeightMagnitude) { + this.minWeightMagnitude = minWeightMagnitude; + } + + public String[] getTrytes() { + return trytes; + } + + public void setTrytes(String[] trytes) { + this.trytes = trytes; + } } diff --git a/src/main/java/jota/dto/request/IotaBroadcastTransactionRequest.java b/src/main/java/jota/dto/request/IotaBroadcastTransactionRequest.java index 42847d9..5a0a5d5 100644 --- a/src/main/java/jota/dto/request/IotaBroadcastTransactionRequest.java +++ b/src/main/java/jota/dto/request/IotaBroadcastTransactionRequest.java @@ -14,4 +14,12 @@ public class IotaBroadcastTransactionRequest extends IotaCommandRequest { public static IotaBroadcastTransactionRequest createBroadcastTransactionsRequest(final String... trytes) { return new IotaBroadcastTransactionRequest(trytes); } + + public String[] getTrytes() { + return trytes; + } + + public void setTrytes(String[] trytes) { + this.trytes = trytes; + } } \ No newline at end of file diff --git a/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java b/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java index b3a72df..71e70fe 100644 --- a/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java +++ b/src/main/java/jota/dto/request/IotaFindTransactionsRequest.java @@ -4,6 +4,38 @@ import jota.IotaAPICommands; public class IotaFindTransactionsRequest extends IotaCommandRequest { + public String[] getBundles() { + return bundles; + } + + public void setBundles(String[] bundles) { + this.bundles = bundles; + } + + public String[] getAddresses() { + return addresses; + } + + public void setAddresses(String[] addresses) { + this.addresses = addresses; + } + + public String[] getTags() { + return tags; + } + + public void setTags(String[] tags) { + this.tags = tags; + } + + public String[] getApprovees() { + return approvees; + } + + public void setApprovees(String[] approvees) { + this.approvees = approvees; + } + private String[] bundles; // List of bundle hashes. The hashes need to be extended to 81chars by padding the hash with 9's. private String[] addresses; private String[] tags; diff --git a/src/main/java/jota/dto/request/IotaGetBalancesRequest.java b/src/main/java/jota/dto/request/IotaGetBalancesRequest.java index 807865d..33d760d 100644 --- a/src/main/java/jota/dto/request/IotaGetBalancesRequest.java +++ b/src/main/java/jota/dto/request/IotaGetBalancesRequest.java @@ -17,5 +17,20 @@ public class IotaGetBalancesRequest extends IotaCommandRequest { return new IotaGetBalancesRequest(threshold, addresses); } + public String[] getAddresses() { + return addresses; + } + + public void setAddresses(String[] addresses) { + this.addresses = addresses; + } + + public Integer getThreshold() { + return threshold; + } + + public void setThreshold(Integer threshold) { + this.threshold = threshold; + } } diff --git a/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java b/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java index d0d323c..704806e 100644 --- a/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java +++ b/src/main/java/jota/dto/request/IotaGetInclusionStateRequest.java @@ -25,4 +25,19 @@ public class IotaGetInclusionStateRequest extends IotaCommandRequest { tips.toArray(new String[]{})); } + public String[] getTransactions() { + return transactions; + } + + public void setTransactions(String[] transactions) { + this.transactions = transactions; + } + + public String[] getTips() { + return tips; + } + + public void setTips(String[] tips) { + this.tips = tips; + } } diff --git a/src/main/java/jota/dto/request/IotaGetTransactionsToApproveRequest.java b/src/main/java/jota/dto/request/IotaGetTransactionsToApproveRequest.java index f597448..fb1b367 100644 --- a/src/main/java/jota/dto/request/IotaGetTransactionsToApproveRequest.java +++ b/src/main/java/jota/dto/request/IotaGetTransactionsToApproveRequest.java @@ -14,4 +14,12 @@ public class IotaGetTransactionsToApproveRequest extends IotaCommandRequest { public static IotaGetTransactionsToApproveRequest createIotaGetTransactionsToApproveRequest(Integer depth) { return new IotaGetTransactionsToApproveRequest(depth); } + + public Integer getDepth() { + return depth; + } + + public void setDepth(Integer depth) { + this.depth = depth; + } } diff --git a/src/main/java/jota/dto/request/IotaGetTrytesRequest.java b/src/main/java/jota/dto/request/IotaGetTrytesRequest.java index b493451..eaa5888 100644 --- a/src/main/java/jota/dto/request/IotaGetTrytesRequest.java +++ b/src/main/java/jota/dto/request/IotaGetTrytesRequest.java @@ -14,4 +14,12 @@ public class IotaGetTrytesRequest extends IotaCommandRequest { public static IotaGetTrytesRequest createGetTrytesRequest(String... hashes) { return new IotaGetTrytesRequest(hashes); } + + public String[] getHashes() { + return hashes; + } + + public void setHashes(String[] hashes) { + this.hashes = hashes; + } } diff --git a/src/main/java/jota/dto/request/IotaNeighborsRequest.java b/src/main/java/jota/dto/request/IotaNeighborsRequest.java index 82c96b1..c81c491 100644 --- a/src/main/java/jota/dto/request/IotaNeighborsRequest.java +++ b/src/main/java/jota/dto/request/IotaNeighborsRequest.java @@ -18,5 +18,13 @@ public class IotaNeighborsRequest extends IotaCommandRequest { public static IotaNeighborsRequest createRemoveNeighborsRequest(String... uris) { return new IotaNeighborsRequest(IotaAPICommands.REMOVE_NEIGHBORS, uris); } + + public String[] getUris() { + return uris; + } + + public void setUris(String[] uris) { + this.uris = uris; + } } diff --git a/src/main/java/jota/dto/request/IotaStoreTransactionsRequest.java b/src/main/java/jota/dto/request/IotaStoreTransactionsRequest.java index 5247894..1b9c55b 100644 --- a/src/main/java/jota/dto/request/IotaStoreTransactionsRequest.java +++ b/src/main/java/jota/dto/request/IotaStoreTransactionsRequest.java @@ -14,4 +14,12 @@ public class IotaStoreTransactionsRequest extends IotaCommandRequest { public static IotaStoreTransactionsRequest createStoreTransactionsRequest(final String... trytes) { return new IotaStoreTransactionsRequest(trytes); } + + public String[] getTrytes() { + return trytes; + } + + public void setTrytes(String[] trytes) { + this.trytes = trytes; + } } diff --git a/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java b/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java index 53081ff..08c56cf 100644 --- a/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java +++ b/src/main/java/jota/dto/response/AnalyzeTransactionResponse.java @@ -7,7 +7,7 @@ import java.util.List; public class AnalyzeTransactionResponse extends AbstractResponse { - private List transactions = new ArrayList(); + private List transactions = new ArrayList<>(); public List getTransactions() { return transactions; diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index f6b38dc..aa6c35f 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -159,11 +159,7 @@ public class Transaction { } public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (((Transaction) obj).getHash().equals(this.getHash())) return true; - return false; + return obj != null && ((Transaction) obj).getHash().equals(this.getHash()); } } \ No newline at end of file diff --git a/src/main/java/jota/pow/ICurl.java b/src/main/java/jota/pow/ICurl.java index 4c2b015..b731b57 100644 --- a/src/main/java/jota/pow/ICurl.java +++ b/src/main/java/jota/pow/ICurl.java @@ -4,12 +4,19 @@ 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); - } + JCurl absorbb(final int[] trits, int offset, int length); + + JCurl absorbb(final int[] trits); + + int[] squeezee(final int[] trits, int offset, int length); + + int[] squeezee(final int[] trits); + + JCurl transform(); + + JCurl reset(); + + int[] getState(); + + void setState(int[] state); +} diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 5f2d97c..8a50475 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -1,8 +1,6 @@ package jota.utils; import jota.model.Transaction; -import jota.pow.JCurl; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,7 +71,7 @@ public class Converter { int[] ret = new int[integers.size()]; for (int i=0; i < ret.length; i++) { - ret[i] = integers.get(i).intValue(); + ret[i] = integers.get(i); } return ret; } diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index b636bb5..226363f 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -2,9 +2,6 @@ package jota.utils; import java.util.List; -import org.apache.commons.lang3.StringUtils; - -import jota.model.Transaction; import jota.model.Transfer; import org.apache.commons.lang3.math.NumberUtils; @@ -81,11 +78,7 @@ public class InputValidator { } // Check if tag is correct trytes of {0,27} trytes - if (!isTrytes(transfer.getTag(), 27)) { - return false; - } - - return true; + return isTrytes(transfer.getTag(), 27); } public static String validateSeed(String seed) { diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index 2a93482..b3c8b00 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -59,9 +59,9 @@ public class IotaAPIUtils { // Get the corresponding keyIndex of the address int keyIndex = 0; - for (int k = 0; k < inputs.size(); k++) { - if (inputs.get(k).getAddress().equals(thisAddress)) { - keyIndex = inputs.get(k).getKeyIndex(); + for (Input input : inputs) { + if (input.getAddress().equals(thisAddress)) { + keyIndex = input.getKeyIndex(); break; } } @@ -90,7 +90,7 @@ public class IotaAPIUtils { // find the second transaction to add the remainder of the signature for (int j = 0; j < bundle.getTransactions().size(); j++) { // Same address as well as value = 0 (as we already spent the input) - if (bundle.getTransactions().get(j).getAddress() == thisAddress && Long.parseLong(bundle.getTransactions().get(j).getValue()) == 0) { + if (bundle.getTransactions().get(j).getAddress().equals(thisAddress) && Long.parseLong(bundle.getTransactions().get(j).getValue()) == 0) { // Use the second 6562 trits int[] secondFragment = Arrays.copyOfRange(key, 6561, 6561 * 2); diff --git a/src/main/java/jota/utils/IotaUnits.java b/src/main/java/jota/utils/IotaUnits.java index 779dde0..d94b235 100644 --- a/src/main/java/jota/utils/IotaUnits.java +++ b/src/main/java/jota/utils/IotaUnits.java @@ -1,9 +1,5 @@ package jota.utils; -/** - * Created by pinpong on 30.11.16. - */ - /** * Table of IOTA units based off of the standard system of Units **/ diff --git a/src/main/java/jota/utils/Parallel.java b/src/main/java/jota/utils/Parallel.java index 1321cdf..f5cdeb7 100644 --- a/src/main/java/jota/utils/Parallel.java +++ b/src/main/java/jota/utils/Parallel.java @@ -25,7 +25,7 @@ public class Parallel { } public static Collection> createCallables(final Iterable elements, final Operation operation) { - List> callables = new LinkedList>(); + List> callables = new LinkedList<>(); for (final T elem : elements) { callables.add(new Callable() { @Override @@ -39,7 +39,7 @@ public class Parallel { return callables; } - public static interface Operation { - public void perform(T pParameter); + public interface Operation { + 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 728271e..ff0fe3d 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -64,12 +64,11 @@ public class Signing { public int[] signatureFragment(int[] normalizedBundleFragment, int[] keyFragment) { - int[] signatureFragment = keyFragment; int[] hash; for (int i = 0; i < 27; i++) { - hash = Arrays.copyOfRange(signatureFragment, i * 243, (i + 1) * 243); + hash = Arrays.copyOfRange(keyFragment, i * 243, (i + 1) * 243); for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) { curl.reset() @@ -78,11 +77,11 @@ public class Signing { } for (int j = 0; j < 243; j++) { - signatureFragment[i * 243 + j] = hash[j]; + System.arraycopy(hash, j, keyFragment, i * 243 + j, 1); } } - return signatureFragment; + return keyFragment; } public int[] address(int[] digests) { @@ -162,8 +161,7 @@ public class Signing { int[] digestBuffer = digest(normalizedBundleFragments[i % 3], Converter.trits(signatureFragments[i])); for (int j = 0; j < 243; j++) { - - digests[i * 243 + j] = digestBuffer[j]; + System.arraycopy(digestBuffer, j, digests, i * 243 + j, 1); } } String address = Converter.trytes(address(digests)); diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index f66eb70..f34ec51 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -65,12 +65,12 @@ public class IotaAPITest { @Before public void createApiClientInstance() { - iotaClient = new IotaAPI(); + iotaClient = new IotaAPI.Builder().build(); } @Test public void shouldCreateIotaApiProxyInstanceWithDefaultValues() { - IotaAPI proxy = new IotaAPI(); + IotaAPI proxy = new IotaAPI.Builder().build(); assertThat(proxy, IsNull.notNullValue()); } From c4ab8522831467fcff1db72b42d2ea39239e19c6 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sat, 21 Jan 2017 23:33:16 +0100 Subject: [PATCH 092/111] fixed timestamp --- src/main/java/jota/IotaAPI.java | 16 +++++----------- src/main/java/jota/model/Bundle.java | 10 ++-------- src/main/java/jota/utils/InputValidator.java | 12 ++++++++---- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 13ea298..e41b10d 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -359,9 +359,8 @@ public class IotaAPI extends IotaAPICoreProxy { msgCopy = StringUtils.substring(msgCopy, 2187, msgCopy.length()); // Pad remainder of fragment - for (int j = 0; fragment.length() < 2187; j++) { - fragment += "9"; - } + + fragment = StringUtils.rightPad(fragment, 2187, '9'); signatureFragments.add(fragment); } @@ -369,9 +368,7 @@ public class IotaAPI extends IotaAPICoreProxy { // Else, get single fragment with 2187 of 9's trytes String fragment = StringUtils.substring(transfer.getMessage(), 0, 2187); - for (int j = 0; fragment.length() < 2187; j++) { - fragment += '9'; - } + fragment = StringUtils.rightPad(fragment, 2187, '9'); signatureFragments.add(fragment); } @@ -383,9 +380,7 @@ public class IotaAPI extends IotaAPICoreProxy { tag = transfer.getTag().isEmpty() ? "999999999999999999999999999" : transfer.getTag(); // Pad for required 27 tryte length - for (int j = 0; tag.length() < 27; j++) { - tag += '9'; - } + tag = StringUtils.rightPad(tag, 27, '9'); // Add first entry to the bundle bundle.addEntry(signatureMessageLength, transfer.getAddress(), transfer.getValue(), tag, timestamp); @@ -551,7 +546,6 @@ public class IotaAPI extends IotaAPICoreProxy { } if (thresholdReached) { - long duration = stopWatch.getElapsedTimeMili(); return GetBalancesAndFormatResponse.create(inputs, totalBalance, stopWatch.getElapsedTimeMili()); } throw new IllegalStateException("Not enough balance"); @@ -794,7 +788,7 @@ public class IotaAPI extends IotaAPICoreProxy { long thisBalance = inputs.get(i).getBalance(); long totalTransferValue = totalValue; long toSubtract = 0 - thisBalance; - long timestamp = (new Date()).getTime(); + long timestamp = (long) Math.floor(Calendar.getInstance().getTimeInMillis() / 1000); // Add input as bundle entry bundle.addEntry(2, inputs.get(i).getAddress(), toSubtract, tag, timestamp); diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index e445627..a296cb8 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -3,6 +3,7 @@ package jota.model; import jota.pow.ICurl; import jota.pow.JCurl; import jota.utils.Converter; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; @@ -31,10 +32,6 @@ public class Bundle implements Comparable { return transactions; } - public void setTransactions(List transactions) { - this.transactions = transactions; - } - public int getLength() { return length; } @@ -49,7 +46,6 @@ public class Bundle implements Comparable { } for (int i = 0; i < signatureMessageLength; i++) { - List transactions = new ArrayList<>(getTransactions()); Transaction trx = new Transaction(address, String.valueOf(i == 0 ? value : 0), tag, String.valueOf(timestamp)); getTransactions().add(trx); } @@ -89,9 +85,7 @@ public class Bundle implements Comparable { String emptySignatureFragment = ""; String emptyHash = EMPTY_HASH; - for (int j = 0; emptySignatureFragment.length() < 2187; j++) { - emptySignatureFragment += '9'; - } + emptySignatureFragment = StringUtils.rightPad(emptySignatureFragment, 2187, '9'); for (int i = 0; i < this.getTransactions().size(); i++) { diff --git a/src/main/java/jota/utils/InputValidator.java b/src/main/java/jota/utils/InputValidator.java index 226363f..4e01cd4 100644 --- a/src/main/java/jota/utils/InputValidator.java +++ b/src/main/java/jota/utils/InputValidator.java @@ -1,10 +1,11 @@ package jota.utils; -import java.util.List; - import jota.model.Transfer; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import java.util.List; + /** * Created by pinpong on 02.12.16. */ @@ -82,8 +83,11 @@ public class InputValidator { } public static String validateSeed(String seed) { - if (seed.length() > 81) return null; - while (seed.length() < 81) seed += 9; + if (seed.length() > 81) + return null; + + seed = StringUtils.rightPad(seed, 81, '9'); + return seed; } } From cb0aa17f1c4d6fcfeb11af94e4ac8b2e7b8dbe30 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 22 Jan 2017 00:04:32 +0100 Subject: [PATCH 093/111] refactored --- src/main/java/jota/model/Bundle.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index a296cb8..f4b86d8 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -11,7 +11,7 @@ import java.util.List; /** * Created by pinpong on 09.12.16. */ -public class Bundle implements Comparable { +public class Bundle implements Comparable { private List transactions; private int length; @@ -141,11 +141,7 @@ public class Bundle implements Comparable { } @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; + public int compareTo(Bundle o) { + return this.getTransactions().get(0).getTimestamp().compareTo(o.getTransactions().get(0).getTimestamp()); } } From 3474ee69ccc5c1fb4ac4c8427be8a4e658c2e097 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 00:24:35 +0100 Subject: [PATCH 094/111] removed unused param --- src/main/java/jota/IotaAPI.java | 16 +++++++--------- src/test/java/jota/IotaAPITest.java | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index e41b10d..4c156c4 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -433,7 +433,7 @@ public class IotaAPI extends IotaAPICoreProxy { // confirm that the inputs exceed the threshold else { - @SuppressWarnings("unchecked") GetBalancesAndFormatResponse newinputs = getInputs(seed, Collections.EMPTY_LIST, 0, 0, totalValue); + @SuppressWarnings("unchecked") GetBalancesAndFormatResponse newinputs = getInputs(seed, 0, 0, totalValue); // If inputs with enough balance return addRemainder(seed, newinputs.getInput(), bundle, tag, totalValue, null, signatureFragments); } @@ -465,7 +465,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @property {int} end Ending key index * @property {int} threshold Min balance required **/ - public GetBalancesAndFormatResponse getInputs(String seed, final List balances, int start, int end, int threshold) { + public GetBalancesAndFormatResponse getInputs(String seed, int start, int end, int threshold) { StopWatch stopWatch = new StopWatch(); // validate the seed if (!InputValidator.isTrytes(seed, 0)) { @@ -497,7 +497,7 @@ public class IotaAPI extends IotaAPICoreProxy { allAddresses.add(address); } - return getBalanceAndFormat(allAddresses, balances, threshold, start, end, stopWatch); + return getBalanceAndFormat(allAddresses, threshold, start, end, stopWatch); } // Case 2: iterate till threshold || end // @@ -506,18 +506,16 @@ public class IotaAPI extends IotaAPICoreProxy { // 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, stopWatch); + return getBalanceAndFormat(res.getAddresses(), 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, StopWatch stopWatch) { + public GetBalancesAndFormatResponse getBalanceAndFormat(final List addresses, long threshold, int start, int end, StopWatch stopWatch) { - if (balances == null || balances.isEmpty()) { - GetBalancesResponse getBalancesResponse = getBalances(100, addresses); - balances = Arrays.asList(getBalancesResponse.getBalances()); - } + GetBalancesResponse getBalancesResponse = getBalances(100, addresses); + List balances = Arrays.asList(getBalancesResponse.getBalances()); // If threshold defined, keep track of whether reached or not // else set default to true diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index f34ec51..cae01b1 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -77,7 +77,7 @@ public class IotaAPITest { @Test public void shouldGetInputs() { - GetBalancesAndFormatResponse res = iotaClient.getInputs(TEST_SEED1, null, 0, 0, 0); + GetBalancesAndFormatResponse res = iotaClient.getInputs(TEST_SEED1, 0, 0, 0); System.out.println(res); assertThat(res, IsNull.notNullValue()); assertThat(res.getTotalBalance(), IsNull.notNullValue()); From 5d1e4aae0c5f30e5bfda1490ad05776ab101aac9 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 13:59:56 +0100 Subject: [PATCH 095/111] correct error handling for addremainder --- pom.xml | 1 + src/main/java/jota/IotaAPI.java | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index d3b98e8..a3b9207 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,7 @@ 4.12 test + diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 4c156c4..5955d38 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -4,6 +4,7 @@ import jota.dto.response.*; import jota.error.ArgumentException; import jota.error.InvalidBundleException; import jota.error.InvalidSignatureException; +import jota.error.NotEnoughBalanceException; import jota.model.*; import jota.pow.ICurl; import jota.pow.JCurl; @@ -318,7 +319,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @property {string} address Remainder address * @returns {array} trytes Returns bundle trytes **/ - public List prepareTransfers(String seed, final List transfers, String remainder, List inputs) { + public List prepareTransfers(String seed, final List transfers, String remainder, List inputs) throws NotEnoughBalanceException { // Input validation of transfers object if (!InputValidator.isTransfersCollectionCorrect(transfers)) { @@ -687,7 +688,7 @@ public class IotaAPI extends IotaAPICoreProxy { return getInclusionStates(hashes, latestMilestone); } - public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, final List transfers, Input[] inputs, String address) { + public SendTransferResponse sendTransfer(String seed, int depth, int minWeightMagnitude, final List transfers, Input[] inputs, String address) throws NotEnoughBalanceException { StopWatch stopWatch = new StopWatch(); List trytes = prepareTransfers(seed, transfers, address, inputs == null ? null : Arrays.asList(inputs)); @@ -780,7 +781,7 @@ public class IotaAPI extends IotaAPICoreProxy { final String tag, final long totalValue, final String remainderAddress, - final List signatureFragments) { + final List signatureFragments) throws NotEnoughBalanceException { for (int i = 0; i < inputs.size(); i++) { long thisBalance = inputs.get(i).getBalance(); @@ -824,7 +825,7 @@ public class IotaAPI extends IotaAPICoreProxy { totalTransferValue -= thisBalance; } } - return null; + throw new NotEnoughBalanceException(); } public static class Builder extends IotaAPICoreProxy.Builder { From a1a5a1de8fb1d73f594f63d85d8e3af62f2d6137 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 14:08:42 +0100 Subject: [PATCH 096/111] fixed addremainder --- src/main/java/jota/IotaAPI.java | 2 +- src/test/java/jota/IotaAPITest.java | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 5955d38..8f21e02 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -783,9 +783,9 @@ public class IotaAPI extends IotaAPICoreProxy { final String remainderAddress, final List signatureFragments) throws NotEnoughBalanceException { + long totalTransferValue = totalValue; for (int i = 0; i < inputs.size(); i++) { long thisBalance = inputs.get(i).getBalance(); - long totalTransferValue = totalValue; long toSubtract = 0 - thisBalance; long timestamp = (long) Math.floor(Calendar.getInstance().getTimeInMillis() / 1000); diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index cae01b1..6af415e 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -6,6 +6,7 @@ import jota.dto.response.*; import jota.error.ArgumentException; import jota.error.InvalidBundleException; import jota.error.InvalidSignatureException; +import jota.error.NotEnoughBalanceException; import jota.model.Bundle; import jota.model.Transaction; import jota.model.Transfer; @@ -98,7 +99,12 @@ public class IotaAPITest { 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 = iotaClient.prepareTransfers(TEST_SEED1, transfers, null, null); + List trytes = null; + try { + trytes = iotaClient.prepareTransfers(TEST_SEED1, transfers, null, null); + } catch (NotEnoughBalanceException e) { + e.printStackTrace(); + } Assert.assertNotNull(trytes); assertThat(trytes.isEmpty(), Is.is(false)); } @@ -132,6 +138,7 @@ public class IotaAPITest { } } } + /* @Test public void shouldSendTrytes() { From 572cf556805644c197e4af19bdd815349ea42170 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 14:31:52 +0100 Subject: [PATCH 097/111] slightly improved error handling --- src/main/java/jota/IotaAPI.java | 23 ++++++++----------- .../java/jota/error/NoAddressException.java | 11 +++++++++ .../java/jota/error/NoNodeInfoException.java | 11 +++++++++ .../jota/error/NoTransactionExcpection.java | 11 +++++++++ 4 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 src/main/java/jota/error/NoAddressException.java create mode 100644 src/main/java/jota/error/NoNodeInfoException.java create mode 100644 src/main/java/jota/error/NoTransactionExcpection.java diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 8f21e02..9e9682b 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -1,10 +1,7 @@ package jota; import jota.dto.response.*; -import jota.error.ArgumentException; -import jota.error.InvalidBundleException; -import jota.error.InvalidSignatureException; -import jota.error.NotEnoughBalanceException; +import jota.error.*; import jota.model.*; import jota.pow.ICurl; import jota.pow.JCurl; @@ -95,7 +92,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @property {bool} inclusionStates returns confirmation status of all transactions * @returns {object} success **/ - public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoAddressException, NoTransactionExcpection, NoNodeInfoException { StopWatch stopWatch = new StopWatch(); // validate & if needed pad seed if ((seed = InputValidator.validateSeed(seed)) == null) { @@ -119,10 +116,10 @@ public class IotaAPI extends IotaAPICoreProxy { System.out.println("GetTransfers after bundlesFromAddresses " + sw.getElapsedTimeMili() + " ms"); return GetTransferResponse.create(bundles, stopWatch.getElapsedTimeMili()); } - return null; + throw new NoAddressException(); } - public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException { + public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoTransactionExcpection, NoNodeInfoException { List trxs = findTransactionObjects(addresses); // set of tail transactions @@ -278,10 +275,10 @@ public class IotaAPI extends IotaAPICoreProxy { * @returns {function} callback * @returns {object} success **/ - public List findTransactionObjects(String[] input) { + public List findTransactionObjects(String[] input) throws NoTransactionExcpection { FindTransactionResponse ftr = findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) - return null; + throw new NoTransactionExcpection(); // get the transaction objects of the transactions return getTransactionsObjects(ftr.getHashes()); @@ -297,10 +294,10 @@ public class IotaAPI extends IotaAPICoreProxy { * @returns {function} callback * @returns {object} success **/ - public List findTransactionObjectsByBundle(String[] input) { + public List findTransactionObjectsByBundle(String[] input) throws NoTransactionExcpection { FindTransactionResponse ftr = findTransactions(null, null, null, input); if (ftr == null || ftr.getHashes() == null) - return null; + throw new NoTransactionExcpection(); // get the transaction objects of the transactions return getTransactionsObjects(ftr.getHashes()); @@ -679,9 +676,9 @@ public class IotaAPI extends IotaAPICoreProxy { * @returns {function} callback * @returns {array} state **/ - public GetInclusionStateResponse getLatestInclusion(String[] hashes) { + public GetInclusionStateResponse getLatestInclusion(String[] hashes) throws NoNodeInfoException { GetNodeInfoResponse getNodeInfoResponse = getNodeInfo(); - if (getNodeInfoResponse == null) return null; + if (getNodeInfoResponse == null) throw new NoNodeInfoException(); String[] latestMilestone = {getNodeInfoResponse.getLatestSolidSubtangleMilestone()}; diff --git a/src/main/java/jota/error/NoAddressException.java b/src/main/java/jota/error/NoAddressException.java new file mode 100644 index 0000000..93752b8 --- /dev/null +++ b/src/main/java/jota/error/NoAddressException.java @@ -0,0 +1,11 @@ +package jota.error; + +/** + * Created by Adrian on 22.01.2017. + */ +public class NoAddressException extends BaseException { + + public NoAddressException() { + super("Not address found for the provided seed"); + } +} \ No newline at end of file diff --git a/src/main/java/jota/error/NoNodeInfoException.java b/src/main/java/jota/error/NoNodeInfoException.java new file mode 100644 index 0000000..920c6f3 --- /dev/null +++ b/src/main/java/jota/error/NoNodeInfoException.java @@ -0,0 +1,11 @@ +package jota.error; + +/** + * Created by Adrian on 22.01.2017. + */ +public class NoNodeInfoException extends BaseException { + + public NoNodeInfoException() { + super("Node info could not be retrieved"); + } +} \ No newline at end of file diff --git a/src/main/java/jota/error/NoTransactionExcpection.java b/src/main/java/jota/error/NoTransactionExcpection.java new file mode 100644 index 0000000..f2b3138 --- /dev/null +++ b/src/main/java/jota/error/NoTransactionExcpection.java @@ -0,0 +1,11 @@ +package jota.error; + +/** + * Created by Adrian on 22.01.2017. + */ +public class NoTransactionExcpection extends BaseException { + + public NoTransactionExcpection() { + super("Not transactions for the provided seed"); + } +} From 499cfea0e1f35157160231caa4b9bb6a1128a443 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 14:41:39 +0100 Subject: [PATCH 098/111] fixed gettransfer handling for seed without transactions --- src/main/java/jota/IotaAPI.java | 14 +++++++------- .../jota/error/NoInclusionStatesExcpection.java | 11 +++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 src/main/java/jota/error/NoInclusionStatesExcpection.java diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 9e9682b..18a9279 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -92,7 +92,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @property {bool} inclusionStates returns confirmation status of all transactions * @returns {object} success **/ - public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoAddressException, NoTransactionExcpection, NoNodeInfoException { + public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoAddressException, NoTransactionExcpection, NoNodeInfoException, NoInclusionStatesExcpection { StopWatch stopWatch = new StopWatch(); // validate & if needed pad seed if ((seed = InputValidator.validateSeed(seed)) == null) { @@ -119,7 +119,7 @@ public class IotaAPI extends IotaAPICoreProxy { throw new NoAddressException(); } - public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoTransactionExcpection, NoNodeInfoException { + public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoTransactionExcpection, NoNodeInfoException, NoInclusionStatesExcpection { List trxs = findTransactionObjects(addresses); // set of tail transactions @@ -153,14 +153,15 @@ public class IotaAPI extends IotaAPICoreProxy { // If inclusionStates, get the confirmation status // of the tail transactions, and thus the bundles GetInclusionStateResponse gisr = null; - if (inclusionStates) { + if (tailTxArray != null && tailTxArray.length != 0 && inclusionStates) { try { gisr = getLatestInclusion(tailTxArray); } catch (IllegalAccessError ignored) { - + throw new NoInclusionStatesExcpection(); + } + if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) { + throw new NoInclusionStatesExcpection(); } - if (gisr == null || gisr.getStates() == null || gisr.getStates().length == 0) - throw new ArgumentException("Inclusion states not found"); } final GetInclusionStateResponse finalInclusionStates = gisr; Parallel.For(Arrays.asList(tailTxArray), @@ -230,7 +231,6 @@ public class IotaAPI extends IotaAPICoreProxy { 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())) { diff --git a/src/main/java/jota/error/NoInclusionStatesExcpection.java b/src/main/java/jota/error/NoInclusionStatesExcpection.java new file mode 100644 index 0000000..c79ee4b --- /dev/null +++ b/src/main/java/jota/error/NoInclusionStatesExcpection.java @@ -0,0 +1,11 @@ +package jota.error; + +/** + * Created by Adrian on 22.01.2017. + */ +public class NoInclusionStatesExcpection extends BaseException { + + public NoInclusionStatesExcpection() { + super("No inclusion states for the provided seed"); + } +} From b63bf5f237dc493aa8a541dc56ae666e35959f95 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 22 Jan 2017 14:55:47 +0100 Subject: [PATCH 099/111] fixed tests --- src/test/java/jota/IotaAPITest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index 6af415e..1a2eb55 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -3,10 +3,7 @@ package jota; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jota.dto.response.*; -import jota.error.ArgumentException; -import jota.error.InvalidBundleException; -import jota.error.InvalidSignatureException; -import jota.error.NotEnoughBalanceException; +import jota.error.*; import jota.model.Bundle; import jota.model.Transaction; import jota.model.Transfer; @@ -110,13 +107,13 @@ public class IotaAPITest { } @Test - public void shouldGetLastInclusionState() { + public void shouldGetLastInclusionState() throws NoNodeInfoException { GetInclusionStateResponse res = iotaClient.getLatestInclusion(new String[]{TEST_HASH}); assertThat(res.getStates(), IsNull.notNullValue()); } @Test - public void shouldFindTransactionObjects() { + public void shouldFindTransactionObjects() throws NoTransactionExcpection { List ftr = iotaClient.findTransactionObjects(TEST_ADDRESSES); assertThat(ftr, IsNull.notNullValue()); } @@ -128,7 +125,7 @@ public class IotaAPITest { } @Test - public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException, NoAddressException, NoInclusionStatesExcpection, NoNodeInfoException, NoTransactionExcpection { GetTransferResponse gtr = iotaClient.getTransfers(TEST_SEED1, 0, 0, false); assertThat(gtr.getTransfers(), IsNull.notNullValue()); From 379897900ae4f1d1809224cb6e9695328642f877 Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 22 Jan 2017 15:31:44 +0100 Subject: [PATCH 100/111] minor --- src/main/java/jota/model/Bundle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index f4b86d8..8e3cbe5 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -142,6 +142,6 @@ public class Bundle implements Comparable { @Override public int compareTo(Bundle o) { - return this.getTransactions().get(0).getTimestamp().compareTo(o.getTransactions().get(0).getTimestamp()); + return this.getTransactions().get(0).getTimestamp().compareTo(getTransactions().get(0).getTimestamp()); } -} +} \ No newline at end of file From 6d4605cfe673407982e503910faabe2c9e688200 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 16:45:27 +0100 Subject: [PATCH 101/111] removed brainf***ed piece of code --- src/main/java/jota/IotaAPI.java | 28 ++++++++----------- .../error/BroadcastAndStoreException.java | 11 ++++++++ .../java/jota/error/NoAddressException.java | 11 -------- .../jota/error/NoTransactionExcpection.java | 11 -------- 4 files changed, 23 insertions(+), 38 deletions(-) create mode 100644 src/main/java/jota/error/BroadcastAndStoreException.java delete mode 100644 src/main/java/jota/error/NoAddressException.java delete mode 100644 src/main/java/jota/error/NoTransactionExcpection.java diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index 18a9279..a657fea 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -92,7 +92,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @property {bool} inclusionStates returns confirmation status of all transactions * @returns {object} success **/ - public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoAddressException, NoTransactionExcpection, NoNodeInfoException, NoInclusionStatesExcpection { + public GetTransferResponse getTransfers(String seed, Integer start, Integer end, Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoNodeInfoException, NoInclusionStatesExcpection { StopWatch stopWatch = new StopWatch(); // validate & if needed pad seed if ((seed = InputValidator.validateSeed(seed)) == null) { @@ -100,8 +100,6 @@ public class IotaAPI extends IotaAPICoreProxy { } start = start != null ? 0 : start; - end = end == null ? null : end; - inclusionStates = inclusionStates != null ? inclusionStates : null; if (start > end || end > (start + 500)) { throw new ArgumentException(); @@ -116,10 +114,10 @@ public class IotaAPI extends IotaAPICoreProxy { System.out.println("GetTransfers after bundlesFromAddresses " + sw.getElapsedTimeMili() + " ms"); return GetTransferResponse.create(bundles, stopWatch.getElapsedTimeMili()); } - throw new NoAddressException(); + return GetTransferResponse.create(new Bundle[]{}, stopWatch.getElapsedTimeMili()); } - public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoTransactionExcpection, NoNodeInfoException, NoInclusionStatesExcpection { + public Bundle[] bundlesFromAddresses(String[] addresses, final Boolean inclusionStates) throws ArgumentException, InvalidBundleException, InvalidSignatureException, NoNodeInfoException, NoInclusionStatesExcpection { List trxs = findTransactionObjects(addresses); // set of tail transactions @@ -199,13 +197,13 @@ public class IotaAPI extends IotaAPICoreProxy { * @param trytes * @return a StoreTransactionsResponse */ - public StoreTransactionsResponse broadcastAndStore(final String... trytes) { + public StoreTransactionsResponse broadcastAndStore(final String... trytes) throws BroadcastAndStoreException { try { broadcastTransactions(trytes); } catch (Exception e) { log.error("Impossible to broadcastAndStore, aborting.", e); - throw new IllegalStateException("BroadcastAndStore Illegal state Exception"); + throw new BroadcastAndStoreException(); } return storeTransactions(trytes); } @@ -218,7 +216,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @param {int} minWeightMagnitude * @return */ - public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { + public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { final GetTransactionsToApproveResponse txs = getTransactionsToApprove(depth); // attach to tangle - do pow @@ -226,9 +224,8 @@ public class IotaAPI extends IotaAPICoreProxy { try { broadcastAndStore(res.getTrytes()); - } catch (Exception e) { - log.error("Impossible to sendTrytes, aborting.", e); - throw new IllegalStateException("sendTrytes Illegal state Exception"); + } catch (BroadcastAndStoreException e) { + return new ArrayList<>(); } final List trx = new ArrayList<>(); @@ -275,11 +272,10 @@ public class IotaAPI extends IotaAPICoreProxy { * @returns {function} callback * @returns {object} success **/ - public List findTransactionObjects(String[] input) throws NoTransactionExcpection { + public List findTransactionObjects(String[] input) { FindTransactionResponse ftr = findTransactions(input, null, null, null); if (ftr == null || ftr.getHashes() == null) - throw new NoTransactionExcpection(); - + return new ArrayList<>(); // get the transaction objects of the transactions return getTransactionsObjects(ftr.getHashes()); } @@ -294,10 +290,10 @@ public class IotaAPI extends IotaAPICoreProxy { * @returns {function} callback * @returns {object} success **/ - public List findTransactionObjectsByBundle(String[] input) throws NoTransactionExcpection { + public List findTransactionObjectsByBundle(String[] input) { FindTransactionResponse ftr = findTransactions(null, null, null, input); if (ftr == null || ftr.getHashes() == null) - throw new NoTransactionExcpection(); + return new ArrayList<>(); // get the transaction objects of the transactions return getTransactionsObjects(ftr.getHashes()); diff --git a/src/main/java/jota/error/BroadcastAndStoreException.java b/src/main/java/jota/error/BroadcastAndStoreException.java new file mode 100644 index 0000000..a5b58e6 --- /dev/null +++ b/src/main/java/jota/error/BroadcastAndStoreException.java @@ -0,0 +1,11 @@ +package jota.error; + +/** + * Created by Adrian on 22.01.2017. + */ +public class BroadcastAndStoreException extends BaseException { + + public BroadcastAndStoreException() { + super("Impossible to broadcastAndStore, aborting."); + } +} \ No newline at end of file diff --git a/src/main/java/jota/error/NoAddressException.java b/src/main/java/jota/error/NoAddressException.java deleted file mode 100644 index 93752b8..0000000 --- a/src/main/java/jota/error/NoAddressException.java +++ /dev/null @@ -1,11 +0,0 @@ -package jota.error; - -/** - * Created by Adrian on 22.01.2017. - */ -public class NoAddressException extends BaseException { - - public NoAddressException() { - super("Not address found for the provided seed"); - } -} \ No newline at end of file diff --git a/src/main/java/jota/error/NoTransactionExcpection.java b/src/main/java/jota/error/NoTransactionExcpection.java deleted file mode 100644 index f2b3138..0000000 --- a/src/main/java/jota/error/NoTransactionExcpection.java +++ /dev/null @@ -1,11 +0,0 @@ -package jota.error; - -/** - * Created by Adrian on 22.01.2017. - */ -public class NoTransactionExcpection extends BaseException { - - public NoTransactionExcpection() { - super("Not transactions for the provided seed"); - } -} From c075d0d06ab24899bda588245d347607bd5b17c6 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 22 Jan 2017 16:47:44 +0100 Subject: [PATCH 102/111] fixed last commit --- src/main/java/jota/model/Bundle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 8e3cbe5..2c920bf 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -142,6 +142,6 @@ public class Bundle implements Comparable { @Override public int compareTo(Bundle o) { - return this.getTransactions().get(0).getTimestamp().compareTo(getTransactions().get(0).getTimestamp()); + return this.getTransactions().get(0).getTimestamp().compareTo(o.getTransactions().get(0).getTimestamp()); } } \ No newline at end of file From cc1c17b7038c003459e44d9b5b1dbc2b5ca2519e Mon Sep 17 00:00:00 2001 From: pinpong Date: Sun, 22 Jan 2017 19:35:43 +0100 Subject: [PATCH 103/111] fixed tests --- src/test/java/jota/IotaAPITest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index 1a2eb55..dd1f711 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -113,7 +113,7 @@ public class IotaAPITest { } @Test - public void shouldFindTransactionObjects() throws NoTransactionExcpection { + public void shouldFindTransactionObjects() { List ftr = iotaClient.findTransactionObjects(TEST_ADDRESSES); assertThat(ftr, IsNull.notNullValue()); } @@ -125,7 +125,7 @@ public class IotaAPITest { } @Test - public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException, NoAddressException, NoInclusionStatesExcpection, NoNodeInfoException, NoTransactionExcpection { + public void shouldGetTransfers() throws InvalidBundleException, ArgumentException, InvalidSignatureException, NoInclusionStatesExcpection, NoNodeInfoException { GetTransferResponse gtr = iotaClient.getTransfers(TEST_SEED1, 0, 0, false); assertThat(gtr.getTransfers(), IsNull.notNullValue()); From 3a9ecf464ab2fdf7f345b76996a3dc74c4e02fa5 Mon Sep 17 00:00:00 2001 From: pinpong Date: Mon, 23 Jan 2017 20:20:20 +0100 Subject: [PATCH 104/111] fixed typos --- src/main/java/jota/IotaAPI.java | 4 +-- src/main/java/jota/model/Bundle.java | 4 +-- src/main/java/jota/pow/ICurl.java | 8 ++--- src/main/java/jota/pow/JCurl.java | 12 +++---- src/main/java/jota/utils/Signing.java | 32 +++++++++---------- .../java/jota/utils/TransactionConverter.java | 4 +-- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index a657fea..a2554f4 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -580,7 +580,7 @@ public class IotaAPI extends IotaAPICoreProxy { 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.absorbb(Converter.trits(trxTrytes)); + curl.absorb(Converter.trits(trxTrytes)); // Check if input transaction if (bundleValue < 0) { String address = trx.getAddress(); @@ -605,7 +605,7 @@ public class IotaAPI extends IotaAPICoreProxy { // 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.squeezee(bundleFromTrxs); + curl.squeeze(bundleFromTrxs); String bundleFromTxString = Converter.trytes(bundleFromTrxs); // Check if bundle hash is the same as returned by tx object diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 2c920bf..548251c 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -68,11 +68,11 @@ public class Bundle implements Comparable { 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.absorbb(t, 0, t.length); + curl.absorb(t, 0, t.length); } int[] hash = new int[243]; - curl.squeezee(hash, 0, hash.length); + curl.squeeze(hash, 0, hash.length); String hashInTrytes = Converter.trytes(hash); for (int i = 0; i < this.getTransactions().size(); i++) { diff --git a/src/main/java/jota/pow/ICurl.java b/src/main/java/jota/pow/ICurl.java index b731b57..9534837 100644 --- a/src/main/java/jota/pow/ICurl.java +++ b/src/main/java/jota/pow/ICurl.java @@ -4,13 +4,13 @@ package jota.pow; * Created by Adrian on 07.01.2017. */ public interface ICurl { - JCurl absorbb(final int[] trits, int offset, int length); + JCurl absorb(final int[] trits, int offset, int length); - JCurl absorbb(final int[] trits); + JCurl absorb(final int[] trits); - int[] squeezee(final int[] trits, int offset, int length); + int[] squeeze(final int[] trits, int offset, int length); - int[] squeezee(final int[] trits); + int[] squeeze(final int[] trits); JCurl transform(); diff --git a/src/main/java/jota/pow/JCurl.java b/src/main/java/jota/pow/JCurl.java index 2b6a775..c57f4b8 100644 --- a/src/main/java/jota/pow/JCurl.java +++ b/src/main/java/jota/pow/JCurl.java @@ -15,7 +15,7 @@ public class JCurl implements ICurl { private int[] state = new int[STATE_LENGTH]; - public JCurl absorbb(final int[] trits, int offset, int length) { + public JCurl absorb(final int[] trits, int offset, int length) { do { System.arraycopy(trits, offset, state, 0, length < HASH_LENGTH ? length : HASH_LENGTH); @@ -28,8 +28,8 @@ public class JCurl implements ICurl { - public JCurl absorbb(final int[] trits) { - return absorbb(trits, 0, trits.length); + public JCurl absorb(final int[] trits) { + return absorb(trits, 0, trits.length); } public JCurl transform() { @@ -52,7 +52,7 @@ public class JCurl implements ICurl { return this; } - public int[] squeezee(final int[] trits, int offset, int length) { + public int[] squeeze(final int[] trits, int offset, int length) { do { System.arraycopy(state, 0, trits, offset, length < HASH_LENGTH ? length : HASH_LENGTH); @@ -63,8 +63,8 @@ public class JCurl implements ICurl { return state; } - public int[] squeezee(final int[] trits) { - return squeezee(trits, 0, trits.length); + public int[] squeeze(final int[] trits) { + return squeeze(trits, 0, trits.length); } public int[] getState() { diff --git a/src/main/java/jota/utils/Signing.java b/src/main/java/jota/utils/Signing.java index ff0fe3d..1cf70a5 100644 --- a/src/main/java/jota/utils/Signing.java +++ b/src/main/java/jota/utils/Signing.java @@ -32,10 +32,10 @@ public class Signing { } curl.reset(); - curl.absorbb(seed, 0, seed.length); - curl.squeezee(seed, 0, seed.length); + curl.absorb(seed, 0, seed.length); + curl.squeeze(seed, 0, seed.length); curl.reset(); - curl.absorbb(seed, 0, seed.length); + curl.absorb(seed, 0, seed.length); final List key = new ArrayList<>(); int[] buffer = new int[seed.length]; @@ -44,7 +44,7 @@ public class Signing { while (length-- > 0) { for (int i = 0; i < 27; i++) { - curl.squeezee(buffer, offset, buffer.length); + curl.squeeze(buffer, offset, buffer.length); for (int j = 0; j < 243; j++) { key.add(buffer[j]); } @@ -72,8 +72,8 @@ public class Signing { for (int j = 0; j < 13 - normalizedBundleFragment[i]; j++) { curl.reset() - .absorbb(hash, 0, hash.length) - .squeezee(hash, 0, hash.length); + .absorb(hash, 0, hash.length) + .squeeze(hash, 0, hash.length); } for (int j = 0; j < 243; j++) { @@ -87,8 +87,8 @@ public class Signing { public int[] address(int[] digests) { int[] address = new int[243]; curl.reset() - .absorbb(digests) - .squeezee(address); + .absorb(digests) + .squeeze(address); return address; } @@ -105,15 +105,15 @@ public class Signing { buffer = Arrays.copyOfRange(keyFragment, j * 243, (j + 1) * 243); for (int k = 0; k < 26; k++) { curl.reset() - .absorbb(buffer) - .squeezee(buffer); + .absorb(buffer) + .squeeze(buffer); } System.arraycopy(buffer, 0, keyFragment, j * 243, 243); } curl.reset(); - curl.absorbb(keyFragment, 0, keyFragment.length); - curl.squeezee(buffer, 0, buffer.length); + curl.absorb(keyFragment, 0, keyFragment.length); + curl.squeeze(buffer, 0, buffer.length); System.arraycopy(buffer, 0, digests, i * 243, 243); } @@ -131,12 +131,12 @@ public class Signing { ICurl jCurl = new JCurl(); jCurl.reset(); - jCurl.absorbb(buffer); - jCurl.squeezee(buffer); + jCurl.absorb(buffer); + jCurl.squeeze(buffer); } - curl.absorbb(buffer); + curl.absorb(buffer); } - curl.squeezee(buffer); + curl.squeeze(buffer); return buffer; } diff --git a/src/main/java/jota/utils/TransactionConverter.java b/src/main/java/jota/utils/TransactionConverter.java index 0949072..27c5882 100644 --- a/src/main/java/jota/utils/TransactionConverter.java +++ b/src/main/java/jota/utils/TransactionConverter.java @@ -46,8 +46,8 @@ public class TransactionConverter { // generate the correct transaction hash curl.reset(); - curl.absorbb(transactionTrits, 0, transactionTrits.length); - curl.squeezee(hash, 0, hash.length); + curl.absorb(transactionTrits, 0, transactionTrits.length); + curl.squeeze(hash, 0, hash.length); Transaction trx = new Transaction(); From 6eb7bf62f8a10fe429e058e32dc23c58f3016ab6 Mon Sep 17 00:00:00 2001 From: AZ Date: Mon, 23 Jan 2017 20:38:01 +0100 Subject: [PATCH 105/111] add travis file --- .travis.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..833b3d3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: java +jdk: +- oraclejdk8 +script: mvn package +deploy: + provider: releases + api_key: + secure: l80FJQ+9Kk+ZYZxXcfagFGgnrp8BlnSZNCDv9KqbWYWQ4YL83qULlD1xgewUcEZhxbddR4nIo/gB1HxrdUxyjzHQKd1ysQ54BH9ZM51MqAtmzslz1gg6WNIDElugsY484W/ynAOQ286tq/5Y4bsAtmHaNzRLlf0sUfW1evXVBNFTz+0eLinqd/r0cC6bEFVk0TWXtk2+EcfTsowkyA36QNZhA+l0ti7GpJj5ubG4cd7hO7ktY4yQ130zJ4zrvv9aL6OwpFULGPDSV/wWujxcZm8GlLrJc2kWAHPLfQESt1Vr9ze2P/8n2FPyh9G67KemS8ubdp5XQPTZKALv4a7Zw8QBhJoahFptkqofgxQkDreCWlgwQyJvmfIJ7pFYXzGsdKUsd4aop6EhT44e2vJuYQBI+EUmx9HiW5+tQPsRkwWqyPyfchHu7KCpqGnImkDTjIHHJinB9dyEdQUbkGVVDWv3n8jNXas5IijS6YvMH5PVt6bWwcbAmijrY+a6E7kf/siJHNNyK/uBTL6FZIkkL2jcH6USgrt2KI/xIoBng1c1w000ctGQcXVGUjeURqQeHclLLpst2Td0uR6SgAGLEOxjeQ9ghzQWC/4x9BPW7xf7SkxhESWB2MMTvxma8xaV7hmNSsUK7tHyMLZPGdhDnPuUx2E6eNG4IZzUvcmHI4U= + file_glob: true + file: "/home/travis/build/iotaledger/iota.lib.java/target/jota*.jar" + skip_cleanup: true + on: + tags: true + repo: iotaledger/iota.lib.java + all_branches: true From 34cfec47c014fc1bcd2587846fe7f4acf6d4e51f Mon Sep 17 00:00:00 2001 From: AZ Date: Fri, 27 Jan 2017 16:23:12 +0100 Subject: [PATCH 106/111] fixed getinputs --- src/main/java/jota/IotaAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index a2554f4..dbfd86b 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -329,7 +329,7 @@ public class IotaAPI extends IotaAPICoreProxy { final Bundle bundle = new Bundle(); final List signatureFragments = new ArrayList<>(); - int totalValue = 0; + long totalValue = 0; String tag = ""; // Iterate over all transfers, get totalValue @@ -459,7 +459,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @property {int} end Ending key index * @property {int} threshold Min balance required **/ - public GetBalancesAndFormatResponse getInputs(String seed, int start, int end, int threshold) { + public GetBalancesAndFormatResponse getInputs(String seed, int start, int end, long threshold) { StopWatch stopWatch = new StopWatch(); // validate the seed if (!InputValidator.isTrytes(seed, 0)) { From 6176b0d5569bc9a370da9897bde523f4229979b6 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 29 Jan 2017 20:23:23 +0100 Subject: [PATCH 107/111] refactored --- src/main/java/jota/IotaAPI.java | 26 +++--- ...IotaAPICoreProxy.java => IotaAPICore.java} | 17 ++-- src/main/java/jota/model/Bundle.java | 2 +- src/main/java/jota/model/Transaction.java | 89 ++++++++++++++++++- src/main/java/jota/utils/Converter.java | 25 ------ src/main/java/jota/utils/IotaAPIUtils.java | 2 +- .../java/jota/utils/TransactionConverter.java | 69 -------------- src/test/java/jota/IotaCoreApiTest.java | 10 ++- 8 files changed, 116 insertions(+), 124 deletions(-) rename src/main/java/jota/{IotaAPICoreProxy.java => IotaAPICore.java} (94%) delete mode 100644 src/main/java/jota/utils/TransactionConverter.java diff --git a/src/main/java/jota/IotaAPI.java b/src/main/java/jota/IotaAPI.java index dbfd86b..8bd00fd 100644 --- a/src/main/java/jota/IotaAPI.java +++ b/src/main/java/jota/IotaAPI.java @@ -25,7 +25,7 @@ import java.util.*; * * @author davassi */ -public class IotaAPI extends IotaAPICoreProxy { +public class IotaAPI extends IotaAPICore { private static final Logger log = LoggerFactory.getLogger(IotaAPI.class); private ICurl customCurl; @@ -216,7 +216,7 @@ public class IotaAPI extends IotaAPICoreProxy { * @param {int} minWeightMagnitude * @return */ - public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { + public List sendTrytes(final String[] trytes, final int depth, final int minWeightMagnitude) { final GetTransactionsToApproveResponse txs = getTransactionsToApprove(depth); // attach to tangle - do pow @@ -230,8 +230,8 @@ public class IotaAPI extends IotaAPICoreProxy { final List trx = new ArrayList<>(); - for (final String tx : Arrays.asList(res.getTrytes())) { - trx.add(new TransactionConverter(customCurl).transactionObject(tx)); + for (final String tryte : Arrays.asList(res.getTrytes())) { + trx.add(new Transaction(tryte, customCurl)); } return trx; } @@ -257,7 +257,7 @@ public class IotaAPI extends IotaAPICoreProxy { final List trxs = new ArrayList<>(); for (final String tryte : trytesResponse.getTrytes()) { - trxs.add(new TransactionConverter(customCurl).transactionObject(tryte)); + trxs.add(new Transaction(tryte, customCurl)); } return trxs; } @@ -440,8 +440,8 @@ public class IotaAPI extends IotaAPICoreProxy { List trxb = bundle.getTransactions(); List bundleTrytes = new ArrayList<>(); - for (Transaction tx : trxb) { - bundleTrytes.add(Converter.transactionTrytes(tx)); + for (Transaction trx : trxb) { + bundleTrytes.add(trx.toTrytes()); } Collections.reverse(bundleTrytes); return bundleTrytes; @@ -577,7 +577,7 @@ public class IotaAPI extends IotaAPICoreProxy { throw new ArgumentException("Invalid Bundle"); } - String trxTrytes = Converter.transactionTrytes(trx).substring(2187, 2187 + 162); + String trxTrytes = trx.toTrytes().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)); @@ -644,9 +644,9 @@ public class IotaAPI extends IotaAPICoreProxy { GetBundleResponse bundleResponse = getBundle(transaction); Bundle bundle = new Bundle(bundleResponse.getTransactions(), bundleResponse.getTransactions().size()); - for (Transaction element : bundle.getTransactions()) { + for (Transaction trx : bundle.getTransactions()) { - bundleTrytes.add(Converter.transactionTrytes(element)); + bundleTrytes.add(trx.toTrytes()); } List trxs = sendTrytes(bundleTrytes.toArray(new String[bundleTrytes.size()]), depth, minWeightMagnitude); @@ -719,7 +719,7 @@ public class IotaAPI extends IotaAPICoreProxy { throw new ArgumentException("Bundle transactions not visible"); } - Transaction trx = new TransactionConverter(customCurl).transactionObject(gtr.getTrytes()[0]); + Transaction trx = new Transaction(gtr.getTrytes()[0], customCurl); if (trx == null || trx.getBundle() == null) { throw new ArgumentException("Invalid trytes, could not create object"); } @@ -760,7 +760,7 @@ public class IotaAPI extends IotaAPICoreProxy { throw new ArgumentException("Bundle transactions not visible"); } - Transaction trx = new TransactionConverter(customCurl).transactionObject(gtr.getTrytes()[0]); + Transaction trx = new Transaction(gtr.getTrytes()[0], customCurl); if (trx == null || trx.getBundle() == null) { throw new ArgumentException("Invalid trytes, could not create object"); } @@ -821,7 +821,7 @@ public class IotaAPI extends IotaAPICoreProxy { throw new NotEnoughBalanceException(); } - public static class Builder extends IotaAPICoreProxy.Builder { + public static class Builder extends IotaAPICore.Builder { private ICurl customCurl; public Builder withCustomCurl(ICurl curl) { diff --git a/src/main/java/jota/IotaAPICoreProxy.java b/src/main/java/jota/IotaAPICore.java similarity index 94% rename from src/main/java/jota/IotaAPICoreProxy.java rename to src/main/java/jota/IotaAPICore.java index e87e052..1004eb6 100644 --- a/src/main/java/jota/IotaAPICoreProxy.java +++ b/src/main/java/jota/IotaAPICore.java @@ -13,7 +13,6 @@ 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; @@ -21,14 +20,14 @@ import java.util.concurrent.TimeUnit; /** * Created by Adrian on 15.01.2017. */ -public class IotaAPICoreProxy { +public class IotaAPICore { - private static final Logger log = LoggerFactory.getLogger(IotaAPICoreProxy.class); + private static final Logger log = LoggerFactory.getLogger(IotaAPICore.class); private IotaAPIService service; private String protocol, host, port; - protected IotaAPICoreProxy(final Builder builder) { + protected IotaAPICore(final Builder builder) { protocol = builder.protocol; host = builder.host; port = builder.port; @@ -142,12 +141,6 @@ public class IotaAPICoreProxy { 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(); @@ -192,7 +185,7 @@ public class IotaAPICoreProxy { String protocol, host, port; - public IotaAPICoreProxy build() { + public IotaAPICore build() { if (protocol == null || host == null || port == null) { @@ -205,7 +198,7 @@ public class IotaAPICoreProxy { } } - return new IotaAPICoreProxy(this); + return new IotaAPICore(this); } private boolean checkPropertiesFiles() { diff --git a/src/main/java/jota/model/Bundle.java b/src/main/java/jota/model/Bundle.java index 548251c..93acfae 100644 --- a/src/main/java/jota/model/Bundle.java +++ b/src/main/java/jota/model/Bundle.java @@ -142,6 +142,6 @@ public class Bundle implements Comparable { @Override public int compareTo(Bundle o) { - return this.getTransactions().get(0).getTimestamp().compareTo(o.getTransactions().get(0).getTimestamp()); + return Long.compare(Long.parseLong(this.getTransactions().get(0).getTimestamp()), Long.parseLong(o.getTransactions().get(0).getTimestamp())); } } \ No newline at end of file diff --git a/src/main/java/jota/model/Transaction.java b/src/main/java/jota/model/Transaction.java index aa6c35f..dbe0506 100644 --- a/src/main/java/jota/model/Transaction.java +++ b/src/main/java/jota/model/Transaction.java @@ -1,12 +1,23 @@ package jota.model; +import jota.pow.ICurl; +import jota.pow.JCurl; +import jota.utils.Converter; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; /** * Created by pinpong on 02.12.16. */ public class Transaction { + private static final Logger log = LoggerFactory.getLogger(Transaction.class); + private ICurl customCurl; + private String hash; private String signatureFragments; private String address; @@ -21,8 +32,21 @@ public class Transaction { private String nonce; private Boolean persistence; - public Transaction() { + public Transaction(ICurl curl) { + customCurl = curl; + } + public Transaction() { + customCurl = null; + } + + public Transaction(String trytes) { + transactionObject(trytes); + } + + public Transaction(String trytes, ICurl customCurl) { + transactionObject(trytes); + this.customCurl = customCurl; } public Transaction(String signatureFragments, String currentIndex, String lastIndex, String nonce, String hash, String tag, String timestamp, String trunkTransaction, String branchTransaction, String address, String value, String bundle) { @@ -162,4 +186,67 @@ public class Transaction { return obj != null && ((Transaction) obj).getHash().equals(this.getHash()); } + public String toTrytes() { + int[] valueTrits = Converter.trits(this.getValue(), 81); + + int[] timestampTrits = Converter.trits(this.getTimestamp(), 27); + + + int[] currentIndexTrits = Converter.trits(this.getCurrentIndex(), 27); + + + int[] lastIndexTrits = Converter.trits(this.getLastIndex(), 27); + + + return this.getSignatureFragments() + + this.getAddress() + + Converter.trytes(valueTrits) + + this.getTag() + + Converter.trytes(timestampTrits) + + Converter.trytes(currentIndexTrits) + + Converter.trytes(lastIndexTrits) + + this.getBundle() + + this.getTrunkTransaction() + + this.getBranchTransaction() + + this.getNonce(); + } + + public void transactionObject(final String trytes) { + + if (StringUtils.isEmpty(trytes)) { + log.warn("Warning: empty trytes in input for transactionObject"); + return; + } + + // validity check + for (int i = 2279; i < 2295; i++) { + if (trytes.charAt(i) != '9') { + log.warn("Trytes {} does not seem a valid tryte", trytes); + return; + } + } + + int[] transactionTrits = Converter.trits(trytes); + int[] hash = new int[243]; + + final ICurl curl = customCurl == null ? new JCurl() : customCurl; // we need a fluent JCurl. + + // generate the correct transaction hash + curl.reset(); + curl.absorb(transactionTrits, 0, transactionTrits.length); + curl.squeeze(hash, 0, hash.length); + + this.setHash(Converter.trytes(hash)); + this.setSignatureFragments(trytes.substring(0, 2187)); + this.setAddress(trytes.substring(2187, 2268)); + this.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837))); + this.setTag(trytes.substring(2295, 2322)); + this.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993))); + this.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020))); + this.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047))); + this.setBundle(trytes.substring(2349, 2430)); + this.setTrunkTransaction(trytes.substring(2430, 2511)); + this.setBranchTransaction(trytes.substring(2511, 2592)); + this.setNonce(trytes.substring(2592, 2673)); + } } \ No newline at end of file diff --git a/src/main/java/jota/utils/Converter.java b/src/main/java/jota/utils/Converter.java index 8a50475..a5f5802 100644 --- a/src/main/java/jota/utils/Converter.java +++ b/src/main/java/jota/utils/Converter.java @@ -219,29 +219,4 @@ 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.getCurrentIndex(), 27); - - - int[] lastIndexTrits = Converter.trits(trx.getLastIndex(), 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(); - } - } diff --git a/src/main/java/jota/utils/IotaAPIUtils.java b/src/main/java/jota/utils/IotaAPIUtils.java index b3c8b00..dfc869b 100644 --- a/src/main/java/jota/utils/IotaAPIUtils.java +++ b/src/main/java/jota/utils/IotaAPIUtils.java @@ -111,7 +111,7 @@ public class IotaAPIUtils { // Convert all bundle entries into trytes for (Transaction tx : bundle.getTransactions()) { - bundleTrytes.add(Converter.transactionTrytes(tx)); + bundleTrytes.add(tx.toTrytes()); } Collections.reverse(bundleTrytes); return bundleTrytes; diff --git a/src/main/java/jota/utils/TransactionConverter.java b/src/main/java/jota/utils/TransactionConverter.java deleted file mode 100644 index 27c5882..0000000 --- a/src/main/java/jota/utils/TransactionConverter.java +++ /dev/null @@ -1,69 +0,0 @@ -package jota.utils; - -import jota.model.Transaction; -import jota.pow.ICurl; -import jota.pow.JCurl; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; - -/** - * Created by Adrian on 15.01.2017. - */ -public class TransactionConverter { - private static final Logger log = LoggerFactory.getLogger(TransactionConverter.class); - private ICurl customCurl; - - public TransactionConverter(ICurl curl) { - customCurl = curl; - } - - public TransactionConverter() { - customCurl = null; - } - - public Transaction transactionObject(final String trytes) { - - if (StringUtils.isEmpty(trytes)) { - log.warn("Warning: empty trytes in input for transactionObject"); - return null; - } - - // validity check - for (int i = 2279; i < 2295; i++) { - if (trytes.charAt(i) != '9') { - log.warn("Trytes {} does not seem a valid tryte", trytes); - return null; - } - } - - int[] transactionTrits = Converter.trits(trytes); - int[] hash = new int[243]; - - 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); - - Transaction trx = new Transaction(); - - trx.setHash(Converter.trytes(hash)); - trx.setSignatureFragments(trytes.substring(0, 2187)); - trx.setAddress(trytes.substring(2187, 2268)); - trx.setValue("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6804, 6837))); - trx.setTag(trytes.substring(2295, 2322)); - trx.setTimestamp("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6966, 6993))); - trx.setCurrentIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 6993, 7020))); - trx.setLastIndex("" + Converter.longValue(Arrays.copyOfRange(transactionTrits, 7020, 7047))); - trx.setBundle(trytes.substring(2349, 2430)); - trx.setTrunkTransaction(trytes.substring(2430, 2511)); - trx.setBranchTransaction(trytes.substring(2511, 2592)); - trx.setNonce(trytes.substring(2592, 2673)); - - return trx; - } -} diff --git a/src/test/java/jota/IotaCoreApiTest.java b/src/test/java/jota/IotaCoreApiTest.java index 66918d4..8913816 100644 --- a/src/test/java/jota/IotaCoreApiTest.java +++ b/src/test/java/jota/IotaCoreApiTest.java @@ -16,11 +16,11 @@ 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; + private static IotaAPICore proxy; @Before public void createProxyInstance() { - proxy = new IotaAPICoreProxy.Builder().build(); + proxy = new IotaAPICore.Builder().build(); } @Test @@ -102,6 +102,12 @@ public class IotaCoreApiTest { @Test public void shouldGetInclusionStates() { + GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{"DBPECSH9YLSSTQDGERUHJBBJTKVUDBMTJLG9WPHBINGHIFOSJMDJLARTVOXXWEFQJLLBINOHCZGYFSMUEXWPPMTOFW"}, new String[]{"EJDQOQHMLJGBMFWB9WJSPRCYIGNPO9WRHDCEQXIMPVPIJ9JV9RJGVHNX9EPGXFOOKBABCVMMAAX999999"}); + assertThat(res.getStates(), IsNull.notNullValue()); + } + + @Test(expected = IllegalAccessError.class) + public void shouldNotGetInclusionStates() { GetInclusionStateResponse res = proxy.getInclusionStates(new String[]{TEST_ADDRESS_WITH_CHECKSUM}, new String[]{"DNSBRJWNOVUCQPILOQIFDKBFJMVOTGHLIMLLRXOHFTJZGRHJUEDAOWXQRYGDI9KHYFGYDWQJZKX999999"}); assertThat(res.getStates(), IsNull.notNullValue()); } From 71fce781b26ad12d22100d65bfbf0b82559cf581 Mon Sep 17 00:00:00 2001 From: AZ Date: Sun, 29 Jan 2017 22:30:30 +0100 Subject: [PATCH 108/111] refactored --- src/test/java/jota/IotaAPITest.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/test/java/jota/IotaAPITest.java b/src/test/java/jota/IotaAPITest.java index dd1f711..4ef7c92 100644 --- a/src/test/java/jota/IotaAPITest.java +++ b/src/test/java/jota/IotaAPITest.java @@ -11,6 +11,7 @@ import org.hamcrest.core.Is; import org.hamcrest.core.IsNull; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; @@ -136,18 +137,26 @@ public class IotaAPITest { } } -/* + @Ignore @Test public void shouldSendTrytes() { iotaClient.sendTrytes(new String[]{TEST_TRYTES}, 9, 18); } + @Test(expected = IllegalStateException.class) + public void shouldNotSendTransfer() throws ArgumentException, InvalidSignatureException, InvalidBundleException, NotEnoughBalanceException { + List transfers = new ArrayList<>(); + transfers.add(new jota.model.Transfer(TEST_ADDRESS_WITHOUT_CHECKSUM, 10000990, "JUSTANOTHERTEST", TEST_TAG)); + SendTransferResponse str = iotaClient.sendTransfer(TEST_SEED2, 9, 18, transfers, null, null); + assertThat(str.getSuccessfully(), IsNull.notNullValue()); + } + + @Ignore @Test - public void shouldSendTransfer() throws InvalidBundleException, ArgumentException, InvalidSignatureException { + public void shouldSendTransfer() throws ArgumentException, InvalidSignatureException, InvalidBundleException, NotEnoughBalanceException { List transfers = new ArrayList<>(); 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 From aa685fb2807266caf5bd9b22137501f1af84fb53 Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 1 Feb 2017 22:09:37 +0100 Subject: [PATCH 109/111] removed wrong travis release key --- .travis.yml | 2 -- pom.xml | 10 +++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 833b3d3..964491c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,6 @@ jdk: script: mvn package deploy: provider: releases - api_key: - secure: l80FJQ+9Kk+ZYZxXcfagFGgnrp8BlnSZNCDv9KqbWYWQ4YL83qULlD1xgewUcEZhxbddR4nIo/gB1HxrdUxyjzHQKd1ysQ54BH9ZM51MqAtmzslz1gg6WNIDElugsY484W/ynAOQ286tq/5Y4bsAtmHaNzRLlf0sUfW1evXVBNFTz+0eLinqd/r0cC6bEFVk0TWXtk2+EcfTsowkyA36QNZhA+l0ti7GpJj5ubG4cd7hO7ktY4yQ130zJ4zrvv9aL6OwpFULGPDSV/wWujxcZm8GlLrJc2kWAHPLfQESt1Vr9ze2P/8n2FPyh9G67KemS8ubdp5XQPTZKALv4a7Zw8QBhJoahFptkqofgxQkDreCWlgwQyJvmfIJ7pFYXzGsdKUsd4aop6EhT44e2vJuYQBI+EUmx9HiW5+tQPsRkwWqyPyfchHu7KCpqGnImkDTjIHHJinB9dyEdQUbkGVVDWv3n8jNXas5IijS6YvMH5PVt6bWwcbAmijrY+a6E7kf/siJHNNyK/uBTL6FZIkkL2jcH6USgrt2KI/xIoBng1c1w000ctGQcXVGUjeURqQeHclLLpst2Td0uR6SgAGLEOxjeQ9ghzQWC/4x9BPW7xf7SkxhESWB2MMTvxma8xaV7hmNSsUK7tHyMLZPGdhDnPuUx2E6eNG4IZzUvcmHI4U= file_glob: true file: "/home/travis/build/iotaledger/iota.lib.java/target/jota*.jar" skip_cleanup: true diff --git a/pom.xml b/pom.xml index a3b9207..79c3808 100644 --- a/pom.xml +++ b/pom.xml @@ -4,10 +4,18 @@ 4.0.0 com.iota jota - 1.0.0-RELEASE + 1.0.0-PRERELEASE JOTA JOTA library is a simple Java wrapper around IOTA Node's JSON-REST HTTP interface. + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + 1.7 UTF-8 From 75cf84c65bbad28c034ca029fb5951b70196da93 Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 1 Feb 2017 22:16:04 +0100 Subject: [PATCH 110/111] updated pom version --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 79c3808..31625ee 100644 --- a/pom.xml +++ b/pom.xml @@ -2,9 +2,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.iota + org.iota jota - 1.0.0-PRERELEASE + 0.9.0-RC1 JOTA JOTA library is a simple Java wrapper around IOTA Node's JSON-REST HTTP interface. From 66483eb1d4df47fb113ed66a7c49392ad248e11b Mon Sep 17 00:00:00 2001 From: AZ Date: Wed, 1 Feb 2017 22:26:30 +0100 Subject: [PATCH 111/111] updated readme --- README.md | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c0f5a0e..915be80 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ The JOTA library is a simple Java wrapper around [[IOTA]](http://www.iotatoken.c It allows to connect easily using java directly to a local or a remote [[IOTA node]](https://iota.readme.io/docs/syncing-to-the-network). -* **Latest release:** 1.0.0 Release -* **Compatibility:** in development to be fully compatible with IOTA IRI v1.1.0 +* **Latest release:** 0.9.0 RC1 +* **Compatibility:** fully compatible with IOTA IRI v1.2.4 * **API coverage:** 14 of 14 commands fully implemented * **License:** Apache License 2.0 -* **Readme updated:** 2016-11-12 21:05:02 (UTC) +* **Readme updated:** 2016-01-19 21:05:02 (UTC) A list of all *IOTA* JSON-REST API commands currently supported by jota wrapper can be found in the `Commands` enum (see [here](https://github.com/davassi/JOTA/blob/master/src/main/java/jota/IotaAPICommands.java) for more details). @@ -32,27 +32,33 @@ Other dependencies: Connect to your local node with the default settings is quite straightforward: it requires only 2 lines of code. For example, in order to fetch the Node Info: - IotaApiProxy api = new IotaApiProxy.Builder.build(); + IotaApi api = new IotaApi.Builder.build(); GetNodeInfoResponse response = api.getNodeInfo(); -of if you need to connect to a remote node on https: +of if you need to connect to a remote node: - IotaApiProxy api = new IotaApiProxy.Builder - .protocol("https") + IotaApi api = new IotaApi.Builder + .protocol("http") .nodeAddress("somewhere_over_the_rainbow") - .port(54321) + .port(14265) .build(); GetNodeInfoResponse response = api.getNodeInfo(); -Jota is still *not* in the central maven repository. It will be available when it will cover 100% iota's rest interface. +In order to communicate with *IOTA node*, JOTA needs to be aware of your node's exact configuration. If you dont want to use the builder the easiest way of providing this information is via a `node_config.properties` file, for example: -In order to communicate with *IOTA node*, JOTA needs to be aware of your node's exact configuration. The easiest way of providing this information is via a `node_config.properties` file, for example: - - iota.node.protocol=http + iota.node.protocol=http``****************`` iota.node.host=127.0.0.1 iota.node.port=14265 +Jota is still *not* in the central maven repository. It will be available when it will cover 100% iota's rest interface. + +##Warning + - This is pre-release software! + - There may be performance and stability issues. + - You may loose all your money :) + - Please report any issues using the Issue Tracker" + That's it! ##Examples @@ -63,7 +69,5 @@ There's an extensive list of test coverages on the src/test/java package of the If JOTA has been useful to you and you feel like contributing, consider posting a bug report or a pull request. Alternatively, donations are very welcome too! -* Bitcoin: `3FGCHqhG1SUpgn2eS1Agq2KnxJemWnQFbB` - - - +* Bitcoin (Gianni Davassi): `3FGCHqhG1SUpgn2eS1Agq2KnxJemWnQFbB` +* Bitcoin (Adrian Ziser): `3FGCHqhG1SUpgn2eS1Agq2KnxJemWnQFbB` \ No newline at end of file