mirror of
https://github.com/gosticks/iota.lib.java.git
synced 2025-10-16 11:45:37 +00:00
Implemented broadcastAndStore and sendTrytes
This commit is contained in:
parent
548b311eed
commit
937a2b2e38
@ -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<Transaction> 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;
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<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;
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
162
src/main/java/jota/model/Bundle.java
Normal file
162
src/main/java/jota/model/Bundle.java
Normal file
@ -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<Transaction> transactions;
|
||||
private int length;
|
||||
|
||||
public static String EMPTY_HASH = "999999999999999999999999999999999999999999999999999999999999999999999999999999999";
|
||||
|
||||
|
||||
public Bundle() {
|
||||
this(new ArrayList<Transaction>(), 0);
|
||||
}
|
||||
|
||||
public Bundle(List<Transaction> transactions, int length) {
|
||||
this.transactions = transactions;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public List<Transaction> getTransactions() {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
public void setTransactions(List<Transaction> 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<String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
48
src/main/java/jota/model/Input.java
Normal file
48
src/main/java/jota/model/Input.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,5 +11,4 @@ public class Constants {
|
||||
|
||||
public static int ADDRESS_LENGTH_WITHOUT_CHECKSUM = 81;
|
||||
public static int ADDRESS_LENGTH_WITH_CHECKSUM = 90;
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String> signInputsAndReturn(String seed, List<Input> inputs, Bundle bundle,
|
||||
List<String> 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<String> bundleTrytes = new ArrayList<>();
|
||||
|
||||
// Convert all bundle entries into trytes
|
||||
for (Transaction tx : bundle.getTransactions()) {
|
||||
bundleTrytes.add(IotaAPIUtils.transactionTrytes(tx));
|
||||
}
|
||||
Collections.reverse(bundleTrytes);
|
||||
return bundleTrytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
* <p>
|
||||
* 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"
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
12
src/test/java/jota/SendMessageTest.java
Normal file
12
src/test/java/jota/SendMessageTest.java
Normal file
@ -0,0 +1,12 @@
|
||||
package jota;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class SendMessageTest {
|
||||
|
||||
@Test
|
||||
public void sendMessage() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1
teststore.txt
Normal file
1
teststore.txt
Normal file
@ -0,0 +1 @@
|
||||
curl http://localhost:14265 -X POST -H Content-Type: application/json -d {'command': 'storeTransactions', 'trytes': ['GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCCOYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZWIKIRH9GCOEVZFKNXEVCUCIIWZQCQEUVRZOCMEL9AMGXJNMLJCIA9UWGRPPHCEOPTSVPKPPPCMQXYBHMSODTWUOABPKWFFFQJHCBVYXLHEWPD9YUDFTGNCYAKQKVEZYRBQRBXIAUX9SVEDUKGMTWQIYXRGSWYRK9SRONVGTW9YGHSZRIXWGPCCUCDRMAXBPDFVHSRYWHGB9DQSQFQKSNICGPIPTRZINYRXQAFSWSEWIFRMSBMGTNYPRWFSOIIWWT9IDSELM9JUOOWFNCCSHUSMGNROBFJX9JQ9XT9PKEGQYQAWAFPRVRRVQPUQBHLSNTEFCDKBWRCDX9EYOBB9KPMTLNNQLADBDLZPRVBCKVCYQEOLARJYAGTBFR9QLPKZBOYWZQOVKCVYRGYI9ZEFIQRKYXLJBZJDBJDJVQZCGYQMROVHNDBLGNLQODPUXFNTADDVYNZJUVPGB9LVPJIYLAPBOEHPMRWUIAJXVQOEM9ROEYUOTNLXVVQEYRQWDTQGDLEYFIYNDPRAIXOZEBCS9P99AZTQQLKEILEVXMSHBIDHLXKUOMMNFKPYHONKEYDCHMUNTTNRYVMMEYHPGASPZXASKRUPWQSHDMU9VPS99ZZ9SJJYFUJFFMFORBYDILBXCAVJDPDFHTTTIYOVGLRDYRTKHXJORJVYRPTDH9ZCPZ9ZADXZFRSFPIQKWLBRNTWJHXTOAUOL9FVGTUMMPYGYICJDXMOESEVDJWLMCVTJLPIEKBE9JTHDQWV9MRMEWFLPWGJFLUXI9BXPSVWCMUWLZSEWHBDZKXOLYNOZAPOYLQVZAQMOHGTTQEUAOVKVRRGAHNGPUEKHFVPVCOYSJAWHZU9DRROHBETBAFTATVAUGOEGCAYUXACLSSHHVYDHMDGJP9AUCLWLNTFEVGQGHQXSKEMVOVSKQEEWHWZUDTYOBGCURRZSJZLFVQQAAYQO9TRLFFN9HTDQXBSPPJYXMNGLLBHOMNVXNOWEIDMJVCLLDFHBDONQJCJVLBLCSMDOUQCKKCQJMGTSTHBXPXAMLMSXRIPUBMBAWBFNLHLUJTRJLDERLZFUBUSMF999XNHLEEXEENQJNOFFPNPQ9PQICHSATPLZVMVIWLRTKYPIXNFGYWOJSQDAXGFHKZPFLPXQEHCYEAGTIWIJEZTAVLNUMAFWGGLXMBNUQTOFCNLJTCDMWVVZGVBSEBCPFSM99FLOIDTCLUGPSEDLOKZUAEVBLWNMODGZBWOVQT9DPFOTSKRABQAVOQ9RXWBMAKFYNDCZOJGTCIDMQSQQSODKDXTPFLNOKSIZEOY9HFUTLQRXQMEPGOXQGLLPNSXAUCYPGZMNWMQWSWCKAQYKXJTWINSGPPZG9HLDLEAWUWEVCTVRCBDFOXKUROXH9HXXAXVPEJFRSLOGRVGYZASTEBAQNXJJROCYRTDPYFUIQJVDHAKEG9YACV9HCPJUEUKOYFNWDXCCJBIFQKYOXGRDHVTHEQUMHO999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999RKWEEVD99A99999999A99999999NFDPEEZCWVYLKZGSLCQNOFUSENIXRHWWTZFBXMPSQHEDFWZULBZFEOMNLRNIDQKDNNIELAOXOVMYEI9PGTKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999999TKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999999999999999999999999999999999999999999999999999999999999999999999999999999999999999']}
|
||||
Loading…
Reference in New Issue
Block a user