diff --git a/src/main/java/fucoin/actions/control/ActionDirtyBugFix.java b/src/main/java/fucoin/actions/control/ActionDirtyBugFix.java new file mode 100644 index 0000000000000000000000000000000000000000..1d8ac505d9fc0f7d5a62323f0b7f1d4364811d1f --- /dev/null +++ b/src/main/java/fucoin/actions/control/ActionDirtyBugFix.java @@ -0,0 +1,23 @@ +package fucoin.actions.control; + +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import fucoin.actions.ClientAction; +import fucoin.wallet.AbstractWallet; + +import java.util.List; + +public class ActionDirtyBugFix extends ClientAction { + private List<ActorRef> actorRefList; + + public ActionDirtyBugFix(List<ActorRef> actorRefList) { + this.actorRefList = actorRefList; + } + + @Override + protected void onAction(ActorRef sender, ActorRef self, UntypedActorContext context, AbstractWallet abstractNode) { + actorRefList.forEach(actor -> { + abstractNode.amounts.put(actor, 100); + }); + } +} diff --git a/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java b/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java index 0c7cbc5ca668b0612c0bbac4ba52da35d6ec7552..30c5063519445d28aa81ee5293d41bc67dbbd5d8 100644 --- a/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java +++ b/src/main/java/fucoin/actions/transaction/ActionCommitDistributedCommittedTransfer.java @@ -47,10 +47,10 @@ public class ActionCommitDistributedCommittedTransfer extends ClientAction { if (granted) { if (source.compareTo(self) == 0) { - wallet.getqDigest().offer(amount); wallet.setAmount(wallet.getAmount() - amount); wallet.addTransactionLogMessageSuccess("Sent " + amount + " FUC to " + target.path().name()); } else if (target.compareTo(self) == 0) { + wallet.getqDigest().offer(amount); wallet.setAmount(wallet.getAmount() + amount); wallet.addTransactionLogMessageSuccess("Received " + amount + " FUC from " + source.path().name()); } @@ -70,7 +70,7 @@ public class ActionCommitDistributedCommittedTransfer extends ClientAction { } // recipient should notify a possible observer - if (observer != null && granted) { + if (target.equals(self) && observer != null) { observer.tell(new ActionNotifyObserver(source, target, amount, granted, timestamp, id), self); } //wallet.addLogMsg("wallet.amounts:" + wallet.amounts); diff --git a/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java b/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java index 997178633677c81e8cbfbab8a35e11f9d3b6c86b..94979fc61750fe53067fc85bc84c820f2d5ec168 100644 --- a/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java +++ b/src/main/java/fucoin/actions/transaction/ActionPrepareDistributedCommittedTransfer.java @@ -24,13 +24,28 @@ public class ActionPrepareDistributedCommittedTransfer extends Transaction { @Override protected void onAction(ActorRef sender, ActorRef self, UntypedActorContext context, AbstractWallet wallet) { - boolean granted = amount > 0 && - //sender is supervisor(bank) has always money - (sender.compareTo(source) == 0 - //sender is unknown, might be valid - || (wallet.amounts.containsKey(source) - //sender have enough money - && wallet.amounts.getOrDefault(source, 0) >= amount)); + //check are the constrains + boolean granted = false; + if (amount > 0) { + //the sender is it self + if (self.equals(source) && wallet.getAmount() >= amount) { + granted = true; + } else { + //check if sender have enough money + if (wallet.amounts.containsKey(source)) { + granted = wallet.amounts.getOrDefault(source, 0) >= amount; + } else { + //sender is unknown, might be valid + granted = true; + } + } + } + + //SuperVisor right. + if (amount > 0 && sender.compareTo(source) == 0) { + granted = true; + } + // precautionly update own ledger to prevent double spending (respectively agreeing) Integer sourceAmount = wallet.amounts.getOrDefault(source, 0); @@ -38,6 +53,7 @@ public class ActionPrepareDistributedCommittedTransfer extends Transaction { wallet.amounts.put(source, sourceAmount - amount); wallet.amounts.put(target, targetAmount + amount); + sender.tell(new ActionPrepareDistributedCommittedTransferAnswer(source, target, amount, timestamp, granted, id), self); } diff --git a/src/main/java/fucoin/configurations/AbstractConfiguration.java b/src/main/java/fucoin/configurations/AbstractConfiguration.java index 3032373135fa2b679eebc00fbd700950ccc924fa..dc77bc4679152fb969125ea1625d6ec94fbaa3d2 100644 --- a/src/main/java/fucoin/configurations/AbstractConfiguration.java +++ b/src/main/java/fucoin/configurations/AbstractConfiguration.java @@ -5,10 +5,7 @@ import akka.actor.Props; import akka.pattern.Patterns; import akka.util.Timeout; import fucoin.AbstractNode; -import fucoin.actions.control.ActionAnnounceWalletCreation; -import fucoin.actions.control.ActionWalletGetNeighbours; -import fucoin.actions.control.ActionWalletGetNeighboursAnswer; -import fucoin.actions.control.ActionWalletSendMoney; +import fucoin.actions.control.*; import fucoin.actions.join.ActionTellSupervisor; import fucoin.actions.transaction.ActionGetAmount; import fucoin.actions.transaction.ActionGetAmountAnswer; @@ -38,34 +35,51 @@ public abstract class AbstractConfiguration extends AbstractNode { protected int remainingTransactions; + protected int remainingWalletsToSpawn; + + protected boolean walletGuiSupport = false; + public static Props props(Class configurationClass) { return Props.create(new ConfigurationCreator(configurationClass)); } /** - * Spawns a new wallet and blocks until it has received its initial money + * Spawns a new wallet. * * @throws Exception on timeout */ - ActorRef spawnWallet(String name, boolean createGUI) throws Exception { + ActorRef spawnWallet(String name, boolean guiSupport) throws Exception { + superVisor.tell(new ActionAnnounceWalletCreation(1, self()), self()); Future<Object> future = Patterns.ask(superVisor, new ActionAnnounceWalletCreation(1, self()), timeout); - ActorRef wallet = createWallet(name, createGUI); + ActorRef wallet = createWallet(name, guiSupport); Await.result(future, timeout.duration()); return wallet; } + ActorRef spawnWallet() { + if (remainingWalletsToSpawn <= 0) { + return null; + } + String name = "Wallet" + remainingWalletsToSpawn--; + //superVisor.tell(new ActionAnnounceWalletCreation(), self()); + //Future<Object> future = Patterns.ask(superVisor, new ActionAnnounceWalletCreation(1, self()), timeout); + ActorRef wallet = createWallet(name, walletGuiSupport); + //Await.result(future, timeout.duration()); + return wallet; + } + /** * Creates a wallet without blocking until the wallet was created */ - private ActorRef createWallet(String name, boolean createGUI) { + private ActorRef createWallet(String name, boolean guiSupport) { Props props; int numOfWallets = activeActors.size(); if (numOfWallets == 0) { - props = WalletImpl.props(null, name, createGUI); + props = WalletImpl.props(null, name, guiSupport); } else { ActorRef knownNeighbour = activeActors.get(ThreadLocalRandom.current().nextInt(activeActors.size())); - props = WalletImpl.props(knownNeighbour, name, createGUI); + props = WalletImpl.props(knownNeighbour, name, guiSupport); } ActorRef actorRef = context().actorOf(props, name); @@ -80,19 +94,6 @@ public abstract class AbstractConfiguration extends AbstractNode { return actorRef; } - /** - * Spawn multiple wallets and wait until they all have their initial FUC - * - * @throws Exception on timeout - */ - public void spawnWallets(int n, boolean createGUI) throws Exception { - Future<Object> future = Patterns.ask(superVisor, new ActionAnnounceWalletCreation(n, self()), timeout); - for (int i = 0; i < n; i++) { - String nameOfTheWallet = "Wallet" + String.valueOf(activeActors.size()); - createWallet(nameOfTheWallet, createGUI); - } - Await.result(future, timeout.duration()); - } /** * Fetch a random wallet @@ -120,12 +121,15 @@ public abstract class AbstractConfiguration extends AbstractNode { return; } + System.out.println("Next Random Transaction, " + remainingTransactions + " left."); + remainingTransactions--; try { randomTransaction(); } catch (Exception e) { System.err.println("Error while trying to perform a random transaction: " + e.getMessage()); - remainingTransactions = 0; + //remainingTransactions = 0; + nextRandomTransaction(); } } @@ -148,6 +152,8 @@ public abstract class AbstractConfiguration extends AbstractNode { //cancel here when no neighbour was found. if (recipient == null) { + remainingTransactions++; + nextRandomTransaction(); return; } @@ -189,8 +195,20 @@ public abstract class AbstractConfiguration extends AbstractNode { System.out.println("Observed a " + status + " transaction of " + notification.amount + " FUCs from " + notification.source.path().name() + " to " + notification.target.path().name()); - if (remainingTransactions > 0) { + if (remainingTransactions > 0 && remainingWalletsToSpawn <= 0) { nextRandomTransaction(); + } else if (remainingWalletsToSpawn > 0) { + spawnWallet(); + + try { + // init amount table from the wallets + if (remainingWalletsToSpawn <= 0) { + activeActors.forEach(actorRef -> actorRef.tell(new ActionDirtyBugFix(activeActors), self())); + } + Thread.sleep(400); + } catch (InterruptedException e) { + e.printStackTrace(); + } } } } diff --git a/src/main/java/fucoin/configurations/MassWalletConfiguration.java b/src/main/java/fucoin/configurations/MassWalletConfiguration.java index dc2631707f7014e9673e80dde61dba9fa55b8bab..3ea5b48218bde6cf3170f4584087c5a7a399e5f9 100644 --- a/src/main/java/fucoin/configurations/MassWalletConfiguration.java +++ b/src/main/java/fucoin/configurations/MassWalletConfiguration.java @@ -1,6 +1,5 @@ package fucoin.configurations; -import fucoin.actions.transaction.ActionNotifyObserver; import fucoin.configurations.internal.ConfigurationName; /** @@ -8,28 +7,23 @@ import fucoin.configurations.internal.ConfigurationName; */ @ConfigurationName("Lots of Wallets") public class MassWalletConfiguration extends AbstractConfiguration { - private boolean runRandomTransactions = false; + @Override public void run() { - initSupervisor(); - try { - spawnWallets(20, false); - System.out.println("Wallet spawning done!"); - Thread.sleep(4000); - } catch (Exception e) { - System.out.println("Wallet spawning timed out!"); - } + //Config + remainingWalletsToSpawn = 5; remainingTransactions = 100; - runRandomTransactions = true; - nextRandomTransaction(); - //randomTransactions(100, 10); + + //Start SuperVisor + initSupervisor(); + + //Init spawning of wallets + System.out.println("Start Wallet spawning!"); + spawnWallet(); } @Override public void onReceive(Object message) { - if (message instanceof ActionNotifyObserver && runRandomTransactions) { - nextRandomTransaction(); - } super.onReceive(message); } } diff --git a/src/main/java/fucoin/wallet/AbstractWallet.java b/src/main/java/fucoin/wallet/AbstractWallet.java index 561e3008ebeba574a33738905509268190cf6e62..8f76327e5edab1b8b70c3fd2951b212f2cb0f29d 100644 --- a/src/main/java/fucoin/wallet/AbstractWallet.java +++ b/src/main/java/fucoin/wallet/AbstractWallet.java @@ -2,9 +2,9 @@ package fucoin.wallet; import akka.actor.ActorRef; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import fucoin.AbstractNode; import fucoin.gui.TransactionLogger; -import scala.concurrent.Future; import java.io.Serializable; import java.time.LocalDateTime; @@ -14,7 +14,7 @@ import java.time.LocalDateTime; */ public abstract class AbstractWallet extends AbstractNode implements Serializable, TransactionLogger { - private static final double sCompression = 0.7; + private static final double sCompression = 0.1; private QDigest qDigest = new QDigest(sCompression); /** @@ -131,7 +131,8 @@ public abstract class AbstractWallet extends AbstractNode implements Serializabl public boolean writeSnapshot(LocalDateTime time) { - return super.writeSnapshot(getName(), new Gson().toJson(new Snapshot(this)), time); + return super.writeSnapshot(getName(), + (new GsonBuilder().setPrettyPrinting().create()).toJson(new Snapshot(this)), time); } public Snapshot readSnapShot(LocalDateTime time) { diff --git a/src/main/java/fucoin/wallet/Snapshot.java b/src/main/java/fucoin/wallet/Snapshot.java index 0e4a6864ca7c2cc87992e176ce661ef973f78068..5171e0e24dd46a9b29321f47acd8c0aa540117d7 100644 --- a/src/main/java/fucoin/wallet/Snapshot.java +++ b/src/main/java/fucoin/wallet/Snapshot.java @@ -1,19 +1,28 @@ package fucoin.wallet; +import akka.actor.ActorRef; + import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Set; -public class Snapshot implements Serializable{ +public class Snapshot implements Serializable { private final String name; private final int amount; - private final byte[] qDigest; + private final Set<String> knownNeighbour; + private final HashMap<ActorRef, Integer> knownNeighbourAmounts; private final List<long[]> qDigestVal; + private final byte[] qDigest; + public Snapshot(AbstractWallet wallet) { this.name = wallet.getName(); this.amount = wallet.getAmount(); this.qDigest = QDigest.serialize(wallet.getqDigest()); this.qDigestVal = wallet.getqDigest().toAscRanges(); + this.knownNeighbour = wallet.getKnownNeighbors().keySet(); + this.knownNeighbourAmounts = wallet.amounts; } public String getName() {