Merge pull request #7 from davassi/master

Java lib Improvements
This commit is contained in:
Gianluigi Davassi
2016-12-14 11:38:18 +01:00
committed by GitHub
19 changed files with 395 additions and 123 deletions
+8 -17
View File
@@ -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<String> 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 {
@@ -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");
}
}
@@ -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<String> messages;
public BaseException(String msg) {
super(msg);
}
public BaseException(String msg, Exception cause) {
super(msg, cause);
}
public BaseException(Collection<String> messages) {
super();
this.messages = messages;
}
public BaseException(Collection<String> 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;
}
}
@@ -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");
}
}
+97 -44
View File
@@ -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;
}
}
@@ -1,4 +1,4 @@
package jota.utils;
package jota.pow;
/**
* (c) 2016 Come-from-Beyond
+4 -2
View File
@@ -2,6 +2,8 @@ package jota.utils;
import org.apache.commons.lang3.StringUtils;
import jota.pow.Curl;
/**
* Created by pinpong on 02.12.16.
*/
@@ -22,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) {
@@ -32,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) {
+4 -2
View File
@@ -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;
}
+56 -7
View File
@@ -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;
}
}
+21 -3
View File
@@ -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) {
@@ -17,7 +17,25 @@ 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) + "}$");
}
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;
}
}
+2 -8
View File
@@ -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) {
@@ -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;
}
}
@@ -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();
}
}
+2
View File
@@ -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) {
@@ -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();
}
}
}
@@ -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);
}
}
+11 -14
View File
@@ -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)));
}
}
@@ -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");
}
}
@@ -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);
}
}