diff --git a/src/main/java/iotaFlashWrapper/Helpers.java b/src/main/java/iotaFlashWrapper/Helpers.java index 8692596..88f998c 100644 --- a/src/main/java/iotaFlashWrapper/Helpers.java +++ b/src/main/java/iotaFlashWrapper/Helpers.java @@ -1,5 +1,6 @@ package iotaFlashWrapper; +import com.sun.org.apache.xpath.internal.operations.Mult; import iotaFlashWrapper.Model.*; @@ -8,89 +9,218 @@ import java.util.List; import java.util.stream.Collectors; public class Helpers { - public static ArrayList createTransaction(UserObject user, ArrayList transfers, boolean shouldClose) { - CreateTransactionHelperObject toUse = IotaFlashBridge.updateLeafToRoot(user.getFlash().getRoot()); - if (toUse.getGenerate() != 0) { - // TODO: tell the server to gen new address. - System.out.println("No more addresses in channel."); - } + + + /** + * Get a transaction object. The object contains the address to use and if required the number of new addresses to generate + * @param root multisig address at the top of the tree + * @return Transaction object with address and number of addresses to create. + */ + public static CreateTransactionHelperObject getTransactionHelper(MultisigAddress root) { + return IotaFlashBridge.updateLeafToRoot(root); + } + + + /** + * + * @param transfers + * @param toUse Transaction helper object + * @param user + * @param shouldClose + * @return + */ + public static ArrayList createTransaction(ArrayList transfers, CreateTransactionHelperObject toUse, UserObject user, boolean shouldClose) { + // System.out.println("Creating a transaction of" + transfers.getValue() + " to " + transfers.getAddress()); + System.out.println("[INFO]: using address " + toUse.getAddress().getAddress() + ", with boundle count" + toUse.getAddress().getBundles().size()); ArrayList newTransfers; + FlashObject flash = user.getFlash(); if (shouldClose) { - newTransfers = IotaFlashBridge.close(user.getFlash().getSettlementAddresses(), user.getFlash().getDeposits()); + newTransfers = IotaFlashBridge.close(flash.getSettlementAddresses(), flash.getDeposits()); } else { + // Prepare a new transaction. newTransfers = IotaFlashBridge.prepare( - user.getFlash().getSettlementAddresses(), - user.getFlash().getDeposits(), + flash.getSettlementAddresses(), + flash.getDeposits(), user.getUserIndex(), transfers ); - } + // Compose the transaction. This may also add some management transactions (moving remainder tokens.) ArrayList bundles = IotaFlashBridge.compose( - user.getFlash().getBalance(), - user.getFlash().getDeposits(), - user.getFlash().getOutputs(), + flash.getBalance(), + flash.getDeposits(), + flash.getOutputs(), toUse.getAddress(), - user.getFlash().getRemainderAddress(), - user.getFlash().getTransfers(), + flash.getRemainderAddress(), + flash.getTransfers(), newTransfers, shouldClose ); - return bundles; + + System.out.println("[SUCCESS] Created signatures for user" + user.getUserIndex()); + // Apply the signature of the transaction creater to the current transactions bundle. + ArrayList signatures = IotaFlashBridge.sign(toUse.getAddress(), user.getSeed(), bundles); + + System.out.println("[SUCCESS] Parial applied Signature for user" + user.getUserIndex() + " on transfer bundle"); + // Sign bundle with your USER ONE'S signatures + return IotaFlashBridge.appliedSignatures(bundles, signatures); } - public static ArrayList signTransaction(UserObject user, ArrayList bundles) { - return IotaFlashBridge.sign(user.getFlash().getRoot(), user.getSeed(), bundles); - } -// -// public static ArrayList appliedSignatures(ArrayList bundles, ArrayList signatures) { -// ArrayList clonedBundles = clone(bundles); -// bundles.clone(); -// -// for (int i = 0; i < bundles.size(); i++) { -// Signature sig = signatures.get(i); -// Bundle b = bundles.get(i); -// if (sig == null) { -// continue; -// } -// -// ArrayList transactions = b.getBundles(); -// String addy = transactions.stream().filter(tx -> tx.getValue() < 0).findFirst().get().getAddress(); -// List tmp = transactions.stream() -// .filter(tx -> tx.getAddress().equals(addy)) -// .collect(Collectors.toList()); -// -// tmp = tmp.subList(sig.getIndex(), sig.getIndex() + sig.getSignatureFragments().size()); -// -// for (int j = 0; j < tmp.size(); j++) { -// tmp.get(j).setSignatureFragments(sig.getSignatureFragments().get(j)); -// } -// } -// -// return clonedBundles; -// } + /** + * + * Tree management. + * + */ - public static void applyTransfers(UserObject user, ArrayList bundles) { - FlashObject flash = IotaFlashBridge.applyTransfersToUser(user, bundles); - user.setFlash(flash); - // IotaFlashBridge.applyTransfers( -// user.getFlash().getRoot(), -// user.getFlash().getDeposits(), -// user.getFlash().getOutputs(), -// user.getFlash().getRemainderAddress(), -// user.getFlash().getTransfers(), -// bundles -// ); - } - - public static ArrayList clone(ArrayList bundles) { - ArrayList clonedBundles = new ArrayList<>(); - for (Bundle b : bundles) { - clonedBundles.add(b.clone()); + /** + * + * @param user + * @param toGenerate + * @return + */ + public static ArrayList getNewBranchDigests(UserObject user, int toGenerate) { + ArrayList digests = new ArrayList<>(); + for (int i = 0; i < toGenerate; i++) { + Digest digest = IotaFlashBridge.getDigest(user.getSeed(), user.getIndex(), user.getSecurity()); + System.out.println("USING index for digest: " + user.getIndex() ); + user.incrementIndex(); + digests.add(digest); } - return clonedBundles; + return digests; } + + + /** + * + * @param oneDigests + * @param twoDigests + * @param user + * @param address + * @return + */ + public static MultisigAddress getNewBranch(ArrayList oneDigests, ArrayList twoDigests, UserObject user, MultisigAddress address) { + ArrayList> userDigestList = new ArrayList<>(); + userDigestList.add(oneDigests); + userDigestList.add(twoDigests); + ArrayList multisigs = getMultisigsForUser(userDigestList, user); + + System.out.println("[INFO]: Adding to address " + address.getAddress()); + + // Build flash trees + for (int i = 1; i < multisigs.size(); i++) { + multisigs.get(i - 1).push(multisigs.get(i)); + } + + // Clone the address to avoid overwriting params. + MultisigAddress output = address.clone(); + + // Add new multisigs to address. + output.push(multisigs.get(0)); + + return output; + } + + + /** + * + * Digests and MultisigAddress creation + * + */ + + /** + * Creates initial digests for a user. This will only create digests for a given TREE_DEPTH -> Digests.size == TREE_DEPTH + 1 + * Other transactions will be generated when required. + * @param user user for which the digests should be generated + * @param TREE_DEPTH number of initial digests to generate + * @return digests for provided user. + */ + public static ArrayList getDigestsForUser(UserObject user, int TREE_DEPTH) { + ArrayList digests = new ArrayList<>(); + // Create digests for the start of the channel + for (int i = 0; i < TREE_DEPTH + 1; i++) { + // Create new digest + Digest digest = IotaFlashBridge.getDigest( + user.getSeed(), + user.getIndex(), + user.getSecurity() + ); + user.incrementIndex(); + System.out.println("Adding digest (" + digest.toString() + ") to user " + user.getUserIndex()); + // Increment key index + + digests.add(digest); + } + return digests; + } + + + /** + * + * @param allDigests + * @param currentUser + * @return + */ + public static ArrayList getMultisigsForUser(ArrayList> allDigests, UserObject currentUser) { + + // Generate the first addresses + ArrayList multisigs = new ArrayList(); + + // Loop for all digests. + for (int index = 0; index < allDigests.get(0).size(); index++) { + ArrayList alignedDigests = new ArrayList<>(); + + int securitySum = 0; + + // Loop for all users. + for (int userIndex = 0; userIndex < allDigests.size(); userIndex++) { + Digest digest = allDigests.get(userIndex).get(index); + // Get array of digests for all users. + alignedDigests.add(digest); + securitySum += digest.getSecurity(); + } + + // Create multisgAddr from digests. + MultisigAddress multisigAddress = IotaFlashBridge.composeAddress(alignedDigests); + + // Get digests data for current user. + Digest digest = allDigests.get(currentUser.getUserIndex()).get(index); + + multisigAddress.setIndex(digest.getIndex()); + multisigAddress.setSigningIndex(currentUser.getUserIndex() * digest.getSecurity()); + multisigAddress.setSecuritySum(securitySum); + multisigAddress.setSecurity(digest.getSecurity()); + + System.out.println("Creating address " + multisigAddress.getAddress() + " index" + multisigAddress.getIndex() + " signingIndex: " + multisigAddress.getSigningIndex()); + + multisigs.add(multisigAddress); + } + + return multisigs; + } + + + /** + * + * @param user + * @param multisigAddress + * @return + */ + public static MultisigAddress updateMultisigChildrenForUser(UserObject user, MultisigAddress multisigAddress) { + FlashObject flash = user.getFlash(); + MultisigAddress originAddress = flash.getRoot().find(multisigAddress.getAddress()); + if (originAddress != null) { + + System.out.println("[INFO]: found address in user" + user.getUserIndex() + " data"); + originAddress.setChildren(multisigAddress.getChildren()); + originAddress.setBundles(multisigAddress.getBundles()); + originAddress.setSecurity(multisigAddress.getSecurity()); + return originAddress; + } + return null; + } + + } diff --git a/src/main/java/iotaFlashWrapper/IotaFlashBridge.java b/src/main/java/iotaFlashWrapper/IotaFlashBridge.java index c28a3a8..2c32028 100644 --- a/src/main/java/iotaFlashWrapper/IotaFlashBridge.java +++ b/src/main/java/iotaFlashWrapper/IotaFlashBridge.java @@ -124,7 +124,7 @@ public class IotaFlashBridge { * @param transfers array of all transfers (value, address) pairs * @return */ - public static ArrayList prepare(ArrayList settlementAddresses, ArrayList deposits, int index, ArrayList transfers) { + public static ArrayList prepare(ArrayList settlementAddresses, ArrayList deposits, int index, ArrayList transfers) { // Now put all params into JS ready array. List params = new ArrayList<>(); @@ -145,7 +145,7 @@ public class IotaFlashBridge { * @param deposits * @return */ - public static ArrayList close(ArrayList settlementAddresses, ArrayList deposits) { + public static ArrayList close(ArrayList settlementAddresses, ArrayList deposits) { V8Array saJS = V8ObjectUtils.toV8Array(engine, settlementAddresses); // Deposits V8Array depositsJS = V8ObjectUtils.toV8Array(engine, deposits); @@ -172,16 +172,13 @@ public class IotaFlashBridge { * @return */ public static ArrayList compose(int balance, - List deposits, + List deposits, ArrayList outputs, MultisigAddress root, MultisigAddress remainderAddress, ArrayList history, ArrayList transfers, boolean close) { - - - // Create params. // Now put all params into JS ready array. List params = new ArrayList(); diff --git a/src/main/java/iotaFlashWrapper/Main.java b/src/main/java/iotaFlashWrapper/Main.java index 5151cc5..ebc5ed9 100644 --- a/src/main/java/iotaFlashWrapper/Main.java +++ b/src/main/java/iotaFlashWrapper/Main.java @@ -1,5 +1,6 @@ package iotaFlashWrapper; +import com.sun.org.apache.xpath.internal.operations.Mult; import iotaFlashWrapper.Model.*; import java.io.IOException; @@ -25,7 +26,7 @@ public class Main { // INITIAL CHANNEL CONDITIONS // Security level - int SECURITY = 2; + int SECURITY = 1; // Number of parties taking signing part in the channel int SIGNERS_COUNT = 2; // Flash tree depth @@ -33,252 +34,189 @@ public class Main { // Total channel Balance int CHANNEL_BALANCE = 2000; // Users deposits - ArrayList DEPOSITS = new ArrayList<>(); - DEPOSITS.add(1000); - DEPOSITS.add(1000); + ArrayList DEPOSITS = new ArrayList<>(); + DEPOSITS.add(1000.0); + DEPOSITS.add(1000.0); // Setup users. FlashObject oneFlashObj = new FlashObject(SIGNERS_COUNT, CHANNEL_BALANCE, DEPOSITS); - UserObject oneFlash = new UserObject(0, oneSeed, TREE_DEPTH, oneFlashObj); + UserObject oneFlash = new UserObject(0, oneSeed, TREE_DEPTH, SECURITY, oneFlashObj); FlashObject twoFlashObj = new FlashObject(SIGNERS_COUNT, CHANNEL_BALANCE, DEPOSITS); - UserObject twoFlash = new UserObject(1, twoSeed, TREE_DEPTH, twoFlashObj); + UserObject twoFlash = new UserObject(1, twoSeed, TREE_DEPTH, SECURITY, twoFlashObj); // USER ONE - setupUser(oneFlash, TREE_DEPTH); + ArrayList oneDigests = Helpers.getDigestsForUser(oneFlash, TREE_DEPTH); // USER TWO - setupUser(twoFlash, TREE_DEPTH); + ArrayList twoDigests = Helpers.getDigestsForUser(twoFlash, TREE_DEPTH); ////////////////////////////////// // INITAL MULTISIG // Make an array of digests - ArrayList allUsers = new ArrayList(); - allUsers.add(oneFlash); - allUsers.add(twoFlash); + ArrayList> allUserDigests = new ArrayList<>(); + allUserDigests.add(oneDigests); + allUserDigests.add(twoDigests); - // Create partial digests for users. - createInitialPartialDigests(allUsers, oneFlash); - createInitialPartialDigests(allUsers, twoFlash); - ArrayList oneMultisigs = oneFlash.getMultisigDigests(); - ArrayList twoMultisigs = twoFlash.getMultisigDigests(); + + /*************************************** + User one setup. + ***************************************/ + + // Create multisigs. + ArrayList oneMultisigs = Helpers.getMultisigsForUser(allUserDigests, oneFlash); // Set renainder address. MultisigAddress oneRemainderAddr = oneMultisigs.remove(0); //shiftCopyArray(); oneFlash.getFlash().setRemainderAddress(oneRemainderAddr); - MultisigAddress twoRemainderAddr = twoMultisigs.remove(0); - twoFlash.getFlash().setRemainderAddress(twoRemainderAddr); - // Build flash trees for (int i = 1; i < oneMultisigs.size(); i++) { System.out.println(oneMultisigs.get(i - 1).toString() + " -> " + oneMultisigs.get(i).toString()); oneMultisigs.get(i - 1).push(oneMultisigs.get(i)); } + oneFlash.getFlash().setRoot(oneMultisigs.remove(0)); + + + + /*************************************** + User one setup. + ***************************************/ + + ArrayList twoMultisigs = Helpers.getMultisigsForUser(allUserDigests, twoFlash); + // Set user two remainder addr. + MultisigAddress twoRemainderAddr = twoMultisigs.remove(0); + twoFlash.getFlash().setRemainderAddress(twoRemainderAddr); // Build flash trees for (int i = 1; i < twoMultisigs.size(); i++) { twoMultisigs.get(i - 1).push(twoMultisigs.get(i)); } - - oneFlash.getFlash().setRoot(oneMultisigs.remove(0)); twoFlash.getFlash().setRoot(twoMultisigs.remove(0)); + + + /*************************************** + Setup tettlements. + ***************************************/ + ArrayList settlementAddresses = new ArrayList<>(); settlementAddresses.add(oneSettlement); settlementAddresses.add(twoSettlement); + + + + /*************************************** + Setup tettlements. + ***************************************/ + oneFlash.getFlash().setSettlementAddresses(settlementAddresses); twoFlash.getFlash().setSettlementAddresses(settlementAddresses); // Set digest/key index - oneFlash.setIndex(oneFlash.getPartialDigests().size()); - twoFlash.setIndex(twoFlash.getPartialDigests().size()); + oneFlash.setIndex(oneDigests.size()); + twoFlash.setIndex(twoDigests.size()); - System.out.println("Channel Setup!"); + System.out.println("Channel Setup completed!"); - ArrayList transfers = new ArrayList<>(); - transfers.add(new Transfer(twoSettlement, 1)); - transfers.add(new Transfer(twoSettlement, 400)); - - System.out.println(oneFlash); - - System.out.println("Creating a transaction: 200 to " + twoSettlement); - ArrayList bundles = Helpers.createTransaction(oneFlash, transfers, false); - - ArrayList partialSignedBundles = signTransfer(bundles, oneFlash); - ArrayList signedBundles = signTransfer(partialSignedBundles, twoFlash); - ///////////////////////////////// - /// APPLY SIGNED BUNDLES - - // Apply transfers to User ONE - Helpers.applyTransfers(oneFlash, signedBundles); - - // Save latest channel bundles - oneFlash.setBundles(signedBundles); - - // Apply transfers to User TWO - Helpers.applyTransfers(twoFlash, signedBundles); - // Save latest channel bundles - twoFlash.setBundles(signedBundles); - System.out.println("[SUCCESS] Apply Transfer to flash channel."); + /*************************************** + Create transactions. + ***************************************/ - System.out.println("Transaction Applied!"); -// System.out.println( -// "Transactable tokens: " + -// oneFlash.getFlash().getDeposits().stream().mapToInt(v -> v.intValue()).sum() -// ); + // Create transfer from user one + ArrayList suggestedTransfer; + + // Accept transfers from other user + ArrayList confirmedTransfers; + + // Try to make 10 transfers. + for (int i = 0; i < 10; i++) { + + // Create transaction helper and check if we need to add nodes + CreateTransactionHelperObject helper = Helpers.getTransactionHelper(oneFlash.getFlash().getRoot()); + + // Check if we need to create new addresses. This must be done before a transaction is prepared. + // The createTransaction will then create funding fundles for the new address. + if (helper.getGenerate() != 0) { + System.out.println("[WARN]: generating " + helper.getGenerate() + "new branches!"); + + // Add user one digests. + ArrayList newOneDigests = Helpers.getNewBranchDigests(oneFlash, helper.getGenerate()); + + // Add user two digests + ArrayList newTwoDigests = Helpers.getNewBranchDigests(twoFlash, helper.getGenerate()); + + // Now we can create new multisig addresses + MultisigAddress multisigAddressOne = Helpers.getNewBranch(newOneDigests, newTwoDigests, oneFlash, helper.getAddress()); + MultisigAddress multisigAddressTwo = Helpers.getNewBranch(newOneDigests, newTwoDigests, twoFlash, helper.getAddress()); + + // Find the multisig with the address and append new address to children + Helpers.updateMultisigChildrenForUser(oneFlash, multisigAddressOne); + Helpers.updateMultisigChildrenForUser(twoFlash, multisigAddressTwo); + + // Set the updated multisig as origin of the transaction. + helper.setAddress(multisigAddressOne); + } + + // Create transfers. + ArrayList transfers = new ArrayList<>(); + transfers.add(new Transfer(twoSettlement, 20)); + + // Create a transaction from a transfer. + suggestedTransfer = Helpers.createTransaction(transfers, helper, oneFlash, false); + + System.out.println("[INFO] Created transfer suggestion."); + + // TODO: check here if transaction is valid. + + // If transactions should be signed create signatures. + ArrayList userTwoSignatures = IotaFlashBridge.sign(twoFlash.getFlash().getRoot(), twoFlash.getSeed(), suggestedTransfer); + System.out.println("[INFO] Created user two signatures."); + // TODO: the signatures should be sind to the first user. + + // Apply transfers by all users. + System.out.println("[INFO] Signing transfers."); + ArrayList signedBundlesOne = IotaFlashBridge.appliedSignatures(suggestedTransfer, userTwoSignatures); + ArrayList signedBundlesTwo = IotaFlashBridge.appliedSignatures(suggestedTransfer, userTwoSignatures); + applyTransfers(signedBundlesOne, oneFlash); + applyTransfers(signedBundlesTwo, twoFlash); + + System.out.println("Transaction Applied! Transactable tokens: " + getFlashDeposits(oneFlash)); + } + System.out.println("Closing channel... not yet working..."); -/* - - // Supplying the CORRECT varibles to create a closing bundle - bundles = Helpers.createTransaction( - oneFlash, - oneFlash.getFlash().getSettlementAddresses(), - true - ); - - ///////////////////////////////// - /// SIGN BUNDLES - - // Get signatures for the bundles - oneSignatures = Helpers.signTransaction(oneFlash, bundles) - - // Generate USER TWO'S Singatures - twoSignatures = Helpers.signTransaction(twoFlash, bundles) - - // Sign bundle with your USER ONE'S signatures - signedBundles = transfer.appliedSignatures(bundles, oneSignatures) - - // ADD USER TWOS'S signatures to the partially signed bundles - signedBundles = transfer.appliedSignatures(signedBundles, twoSignatures) - - ///////////////////////////////// - /// APPLY SIGNED BUNDLES + } + public static void applyTransfers(ArrayList signedBundles, UserObject user) { // Apply transfers to User ONE - oneFlash = Helpers.applyTransfers(oneFlash, signedBundles) + FlashObject newFlash = IotaFlashBridge.applyTransfersToUser(user, signedBundles); + + // Set new flash object to user + user.setFlash(newFlash); + // Save latest channel bundles - oneFlash.bundles = signedBundles - - // Apply transfers to User TWO - twoFlash = Helpers.applyTransfers(twoFlash, signedBundles) - // Save latest channel bundles - twoFlash.bundles = signedBundles - - console.log("Channel Closed") - console.log("Final Bundle to be attached: ")*/ + user.setBundles(signedBundles); } - private static ArrayList signTransfer(ArrayList bundles, UserObject user) { - System.out.println("[SUCCESS] Created signatures for users."); - ArrayList oneSignatures = Helpers.signTransaction(user, bundles); - - System.out.println("[SUCCESS] Parial applied Signature for User one on transfer bundle"); - // Sign bundle with your USER ONE'S signatures - ArrayList signedBundles = IotaFlashBridge.appliedSignatures(bundles, oneSignatures); - - return signedBundles; - } - - private static void setupUser(UserObject user, int TREE_DEPTH) { - // Create digests for the start of the channel - for (int i = 0; i < TREE_DEPTH + 1; i++) { - // Create new digest - Digest digest = IotaFlashBridge.getDigest( - user.getSeed(), - user.getIndex(), - user.getSecurity() - ); - System.out.println("Adding digest (" + digest.toString() + ") to user " + user.getUserIndex()); - // Increment key index - user.incrementIndex(); - user.add(digest); + public static double getFlashDeposits(UserObject user) { + double sum = 0; + for (double deposit : user.getFlash().getDeposits()) { + sum += deposit; } + return sum; } - private static void createInitialPartialDigests(ArrayList allUsers, UserObject currentUser) { - // Generate the first addresses - ArrayList oneMultisigs = new ArrayList(); - - - System.out.println("_________________________________________________________________"); - System.out.println("Creating multisigs on user: " + currentUser.getUserIndex()); - int index = 0; - // Create address - for (Digest digest: allUsers.get(index).getPartialDigests()) { - int i = index; - - MultisigAddress addy = IotaFlashBridge.composeAddress( - allUsers.stream().map(u -> u.getPartialDigests().get(i)).collect(Collectors.toCollection(ArrayList::new)) - ); - - System.out.println("Multisig: " + addy.toString()); - - // Add key index in - addy.setIndex(digest.getIndex()); - // Add the signing index to the object IMPORTANT - addy.setSigningIndex(currentUser.getUserIndex() * digest.getSecurity()); - // Get the sum of all digest security to get address security sum - addy.setSecuritySum(allUsers.stream() - .map(u -> u.getPartialDigests().get(i)) - .mapToInt(Digest::getSecurity) - .sum() - ); - addy.setSecurity(digest.getSecurity()); - oneMultisigs.add(addy); - index++; - } - currentUser.setMultisigDigests(oneMultisigs); - } - - private static ArrayList shiftCopyArray(ArrayList input) { - ArrayList output = new ArrayList<>(); - - for (int i = 1; i < input.size(); i++) { - output.add(input.get(i)); - } - - return output; - } - - private static void test() throws IOException { - - System.out.println("IOTA Flash channel tester"); - - String pathToLib = "res/iota.flash.js"; - - System.out.println("Loading lib into V8 engine"); - System.out.println("Lib imported"); - - - System.out.println("Testing getDigest(seed, index, security):"); - Digest digest1 = IotaFlashBridge.getDigest("USERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSER", 0, 2); - Digest digest2 = IotaFlashBridge.getDigest("USERTWOUSERTWOUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSERONEUSER", 0, 2); - System.out.println("Digest1: " + digest1.toString()); - - - System.out.println("Testing composeAddress(digests):"); - ArrayList digests = new ArrayList(); - digests.add(digest1); - digests.add(digest2); - MultisigAddress composedAddr = IotaFlashBridge.composeAddress(digests); - System.out.println("Got multisig addr for digests: " + composedAddr.getAddress() + ", securitySum: " + composedAddr.getSecuritySum()); - - testPrepare(); - } - - private static void testPrepare() { - - System.out.println("Testing prepare()"); - ArrayList settlementAddr = new ArrayList(); - settlementAddr.add("RCZHCRDWMGJPHKROKEGVADVJXPGKEKNJRNLZZFPITUVEWNPGIWNUMKTYKMNB9DCNLWGMJZDNKYQDQKDLC"); - ArrayList depositsPrep = new ArrayList(); - ArrayList transfers = new ArrayList(); - - IotaFlashBridge.prepare(settlementAddr, depositsPrep, 0, transfers); + /** + * acceptTransfer applies signatures of a + * @param bundles half signed transfers + * @param signatures signatures of the second user + */ + public static void acceptTransfer(ArrayList bundles, ArrayList signatures, UserObject user) { + ArrayList signedBundles = IotaFlashBridge.appliedSignatures(bundles, signatures); + applyTransfers(signedBundles, user); } } diff --git a/src/main/java/iotaFlashWrapper/Model/Bundle.java b/src/main/java/iotaFlashWrapper/Model/Bundle.java index 7c56fe9..61e09ab 100644 --- a/src/main/java/iotaFlashWrapper/Model/Bundle.java +++ b/src/main/java/iotaFlashWrapper/Model/Bundle.java @@ -28,12 +28,17 @@ public class Bundle { public Map toMap() { Map map = new HashMap(); + + map.put("bundles", toArrayList()); + return map; + } + + public List toArrayList() { List bundleList = new ArrayList(); for (Transaction b: bundles) { bundleList.add(b.toMap()); } - map.put("bundles", bundleList); - return map; + return bundleList; } public ArrayList getBundles() { diff --git a/src/main/java/iotaFlashWrapper/Model/CreateTransactionHelperObject.java b/src/main/java/iotaFlashWrapper/Model/CreateTransactionHelperObject.java index fb46f65..51e3139 100644 --- a/src/main/java/iotaFlashWrapper/Model/CreateTransactionHelperObject.java +++ b/src/main/java/iotaFlashWrapper/Model/CreateTransactionHelperObject.java @@ -16,4 +16,8 @@ public class CreateTransactionHelperObject { public MultisigAddress getAddress() { return address; } + + public void setAddress(MultisigAddress address) { + this.address = address; + } } \ No newline at end of file diff --git a/src/main/java/iotaFlashWrapper/Model/FlashObject.java b/src/main/java/iotaFlashWrapper/Model/FlashObject.java index d68b810..8f63347 100644 --- a/src/main/java/iotaFlashWrapper/Model/FlashObject.java +++ b/src/main/java/iotaFlashWrapper/Model/FlashObject.java @@ -8,20 +8,20 @@ public class FlashObject { int signersCount = 2; int balance; ArrayList settlementAddresses; - ArrayList deposits; // Clone correctly + ArrayList deposits; ArrayList outputs = new ArrayList(); ArrayList transfers = new ArrayList(); MultisigAddress root; MultisigAddress remainderAddress; - public FlashObject(int signersCount, int balance, ArrayList deposits) { + public FlashObject(int signersCount, int balance, ArrayList deposits) { this.signersCount = signersCount; this.balance = balance; this.deposits = deposits; } - public FlashObject(int signersCount, int balance, ArrayList settlementAddresses, ArrayList deposits, ArrayList outputs, ArrayList transfers, MultisigAddress root, MultisigAddress remainderAddress) { + public FlashObject(int signersCount, int balance, ArrayList settlementAddresses, ArrayList deposits, ArrayList outputs, ArrayList transfers, MultisigAddress root, MultisigAddress remainderAddress) { this.signersCount = signersCount; this.balance = balance; this.settlementAddresses = settlementAddresses; @@ -42,7 +42,7 @@ public class FlashObject { out += "\t" + b + "\n"; } out += "deposits: " + "\n"; - for (Integer b: deposits) { + for (double b: deposits) { out += "\t" + b + "\n"; } @@ -98,7 +98,7 @@ public class FlashObject { return root; } - public ArrayList getDeposits() { + public ArrayList getDeposits() { return deposits; } diff --git a/src/main/java/iotaFlashWrapper/Model/MultisigAddress.java b/src/main/java/iotaFlashWrapper/Model/MultisigAddress.java index 50e7209..8a580be 100644 --- a/src/main/java/iotaFlashWrapper/Model/MultisigAddress.java +++ b/src/main/java/iotaFlashWrapper/Model/MultisigAddress.java @@ -3,6 +3,7 @@ package iotaFlashWrapper.Model; import com.eclipsesource.v8.V8; import com.eclipsesource.v8.V8Object; import com.eclipsesource.v8.utils.V8ObjectUtils; +import com.sun.org.apache.xpath.internal.operations.Mult; import java.util.ArrayList; import java.util.HashMap; @@ -24,7 +25,6 @@ public class MultisigAddress { this.securitySum = securitySum; this.children = new ArrayList(); this.bundles = new ArrayList(); - } public MultisigAddress(String address, int securitySum, ArrayList children) { @@ -34,6 +34,42 @@ public class MultisigAddress { this.bundles = new ArrayList(); } + public MultisigAddress find(String address) { + if (getAddress().equals(address)) { + return this; + } else { + for (MultisigAddress mult: getChildren()) { + MultisigAddress result = mult.find(address); + if (result != null) { + return result; + } + } + } + return null; + } + + public MultisigAddress clone() { + MultisigAddress output = new MultisigAddress(this.getAddress(), this.getSecuritySum()); + + output.setSecurity(this.getSecurity()); + output.setIndex(this.getIndex()); + output.setSigningIndex(this.getSigningIndex()); + // Copy all bundles + ArrayList bundleCopy = new ArrayList<>(); + for (Bundle b : this.getBundles()) { + bundleCopy.add(b.clone()); + } + output.setBundles(bundleCopy); + + // Copy all children + ArrayList childrenCopy = new ArrayList<>(); + for (MultisigAddress child : this.getChildren()) { + childrenCopy.add(child.clone()); + } + output.setChildren(childrenCopy); + return output; + } + public void push(MultisigAddress addr) { children.add(addr); } @@ -53,6 +89,22 @@ public class MultisigAddress { return index; } + public void setAddress(String address) { + this.address = address; + } + + public void setChildren(ArrayList children) { + this.children = children; + } + + public ArrayList getBundles() { + return bundles; + } + + public void setBundles(ArrayList bundles) { + this.bundles = bundles; + } + public int getSigningIndex() { return signingIndex; } @@ -92,7 +144,7 @@ public class MultisigAddress { List bundleList = new ArrayList(); for (Bundle b: bundles) { - bundleList.add(b.getBundles()); + bundleList.add(b.toArrayList()); } map.put("bundles", bundleList); diff --git a/src/main/java/iotaFlashWrapper/Model/UserObject.java b/src/main/java/iotaFlashWrapper/Model/UserObject.java index 9cae4c6..1a7f0ce 100644 --- a/src/main/java/iotaFlashWrapper/Model/UserObject.java +++ b/src/main/java/iotaFlashWrapper/Model/UserObject.java @@ -5,25 +5,27 @@ import java.util.HashMap; import java.util.Map; public class UserObject { - private int userIndex = 1; + private int userIndex; private String seed; private int index = 0; - private int security = 2; - private int depth = 4; + private int security; + private int depth; private ArrayList bundles = new ArrayList(); private ArrayList partialDigests = new ArrayList(); private ArrayList multisigDigests = new ArrayList(); private FlashObject flash; - public UserObject(int userID, String seed, int depth, FlashObject flash) { + public UserObject(int userID, String seed, int depth, int security, FlashObject flash) { this.userIndex = userID; this.seed = seed; this.depth = depth; + this.security = security; this.flash = flash; } - public void incrementIndex() { - index++; + public int incrementIndex() { + this.index = this.index + 1; + return index; } public void add(Digest digest) { diff --git a/src/main/java/iotaFlashWrapper/V8Converter.java b/src/main/java/iotaFlashWrapper/V8Converter.java index da0137b..e0f56d5 100644 --- a/src/main/java/iotaFlashWrapper/V8Converter.java +++ b/src/main/java/iotaFlashWrapper/V8Converter.java @@ -3,6 +3,7 @@ package iotaFlashWrapper; import com.eclipsesource.v8.V8; import com.eclipsesource.v8.V8Array; import com.eclipsesource.v8.V8Object; +import com.eclipsesource.v8.V8ResultUndefined; import com.eclipsesource.v8.utils.V8ObjectUtils; import iotaFlashWrapper.Model.*; @@ -52,7 +53,17 @@ public class V8Converter { ArrayList settlementAddresses = (ArrayList) inputMap.get("settlementAddresses"); MultisigAddress root = multisigAddressFromPropertyMap((Map) inputMap.get("root")); MultisigAddress remainderAddress = multisigAddressFromPropertyMap((Map) inputMap.get("remainderAddress")); - ArrayList deposits = (ArrayList) inputMap.get("deposits"); + ArrayList deposits = new ArrayList<>(); + if (inputMap.get("deposits") instanceof ArrayList) { + Object depositEntry = inputMap.get("deposits"); + if (((ArrayList) depositEntry).size() > 0 && ((ArrayList) depositEntry).get(0) instanceof Integer) { + for (int val: (ArrayList) depositEntry) { + deposits.add(new Double(val)); + } + } else { + deposits = (ArrayList) depositEntry; + } + } ArrayList transfers = bundleListFromArrayList((ArrayList) inputMap.get("transfers")); ArrayList outputs = bundleListFromArrayList((ArrayList) inputMap.get("outputs")); @@ -84,7 +95,17 @@ public class V8Converter { ArrayList ret = new ArrayList<>(); for (Object o: input) { - ret.add(bundleFromArrayList((ArrayList) o)); + if (o instanceof Map) { + if (((Map) o).get("bundles") instanceof String) { + ArrayList bundles = (ArrayList) ((Map) o).get("bundles"); + ret.add(bundleFromArrayList(bundles)); + } else { + continue; + } + } + if (o instanceof ArrayList) { + ret.add(bundleFromArrayList((ArrayList) o)); + } } @@ -92,6 +113,10 @@ public class V8Converter { } public static MultisigAddress multisigAddressFromV8Object(V8Object input) { + if (input.isUndefined()) { + System.out.println("[ERROR]: could not parse object"); + return null; + } Map multiSigMap = V8ObjectUtils.toMap(input); return multisigAddressFromPropertyMap(multiSigMap); } @@ -101,7 +126,6 @@ public class V8Converter { String addr = (String) propMap.get("address"); int secSum = (Integer) propMap.get("securitySum"); - ArrayList children = new ArrayList<>(); for (Object child: (ArrayList) propMap.get("children")) { @@ -111,6 +135,23 @@ public class V8Converter { MultisigAddress multisig = new MultisigAddress(addr, secSum, children); + if (propMap.get("bundles") instanceof ArrayList) { + ArrayList bundles = new ArrayList<>(); + for (Object bundle: (ArrayList) propMap.get("bundles")) { + Bundle b = new Bundle(); + if (!(bundle instanceof ArrayList)) { + continue; + } else { + for (Object transactionMap: (ArrayList) bundle) { + b.getBundles().add(transactionFromObject(transactionMap)); + } + } + bundles.add(b); + } + + multisig.setBundles(bundles); + } + if (propMap.get("index") != null) { multisig.setIndex((Integer) propMap.get("index")); } @@ -118,6 +159,10 @@ public class V8Converter { multisig.setSigningIndex((Integer) propMap.get("signingIndex")); } + if (propMap.get("security") instanceof Integer) { + multisig.setSecurity((Integer) propMap.get("security")); + } + return multisig; } @@ -126,6 +171,10 @@ public class V8Converter { // Parse return as array of bundles ArrayList returnBundles = new ArrayList<>(); for (Object bundleItem: inputList) { + if (!(bundleItem instanceof ArrayList)) { + System.out.println("[ERROR]: got undefined for bunle"); + continue; + } ArrayList bundleContent = (ArrayList) bundleItem; ArrayList returnedTransactions = new ArrayList<>();