mirror of
https://github.com/gosticks/iota.lib.java.git
synced 2026-08-19 15:50:19 +00:00
[WIP ]tryfix getInputs, start to finish the god damn java lib
This commit is contained in:
@@ -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:
|
||||
*
|
||||
* <p>
|
||||
* IotaApiProxy api = IotaApiProxy.Builder
|
||||
* .protocol("http")
|
||||
* .nodeAddress("localhost")
|
||||
* .port(12345)
|
||||
* .build();
|
||||
*
|
||||
* <p>
|
||||
* 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<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();
|
||||
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<String> 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<Input>(), 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<int> inputAddresses = new ArrayList();
|
||||
for (int input : inputs) {
|
||||
inputAddresses.add(input);
|
||||
}
|
||||
|
||||
GetBalancesResponse balances = getBalances(100, inputAddresses);
|
||||
|
||||
List<Input> confirmedInputs = new ArrayList<Input>();
|
||||
|
||||
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<String> 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<Input> inputs, long totalValue, Bundle bundle, String tag,
|
||||
String remainderAddress, List<String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class GetNewAddressResponse extends AbstractResponse {
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<String> getAddress() {
|
||||
public List<String> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Input> inputsList;
|
||||
private long totalBalance;
|
||||
|
||||
public Inputs(List<Input> inputsList, long totalBalance) {
|
||||
this.inputsList = inputsList;
|
||||
this.totalBalance = totalBalance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Gson().toJson(this);
|
||||
}
|
||||
|
||||
public List<Input> getInputsList() {
|
||||
return inputsList;
|
||||
}
|
||||
|
||||
public void setInputsList(List<Input> inputsList) {
|
||||
inputsList = inputsList;
|
||||
}
|
||||
|
||||
public long getTotalBalance() {
|
||||
return totalBalance;
|
||||
}
|
||||
|
||||
public void setTotalBalance(long totalBalance) {
|
||||
totalBalance = totalBalance;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<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
|
||||
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);
|
||||
}
|
||||
}*/
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user