diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9c80ff7151c0c744b384abb047561d4d60cce3f8 Binary files /dev/null and b/.DS_Store differ diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fbb6cd10b24a60f472c9b06770d7b373e8fec9d2 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/java/fr/miage/App.java b/src/main/java/fr/miage/App.java old mode 100644 new mode 100755 index 831f4f34bf221e164863de9678721779f9e10880..e0cad8e119eec02f02fdc838d449c085c2cef9ad --- a/src/main/java/fr/miage/App.java +++ b/src/main/java/fr/miage/App.java @@ -1,5 +1,6 @@ package fr.miage; +import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Set; @@ -9,23 +10,57 @@ import java.util.Set; */ public class App { - public static void main( String[] args ) + public static void main( String[] args ) throws NoSuchAlgorithmException, InterruptedException { System.out.println("Début de la blockchain"); // Création de 2 wallets - Wallet bobWallet = new Wallet("publicKey1", "privateKey1"); - Wallet aliceWallet = new Wallet("publicKey2", "privateKey2"); + Wallet bobWallet = new Wallet("jesuislacleprivedebob", "bob"); + //Wallet aliceWallet = new Wallet("je suis la clé privé de alice", "alice"); + Set<Wallet> wallets = new HashSet<Wallet>() { { add(bobWallet); - add(aliceWallet); + //add(aliceWallet); } }; - // Création de la blockchain Blockchain blockchain = new Blockchain("BloBlockchain", wallets); - System.out.println(blockchain); - // MinageManager minageManager = new MinageManager(blockchain); - // minageManager.mineABloc(); + + // System.out.println("Utxos du wallet de bob : " + bobWallet.getUtxos()); + // System.out.println("Utxos du wallet de alice : " + aliceWallet.getUtxos()); + // Transaction transaction = new Transaction(bobWallet, aliceWallet, 2, EnumTypeTransaction.NORMAL); + // System.out.println("Transaction : "); + // System.out.println("Bob envoie : " + transaction.getInputs()); + // System.out.println("Alice reçoit : " + transaction.getOutputs()); + // System.out.println(transaction); + + + // int i = 1; + // while(blockchain.transactionsPool.size() <20){ + // System.out.println("Transaction n°" + i); + // blockchain.createTrasaction(); + // i++; + // } + + // // print all utxo in the utxo set + // for (UTxO utxo : Blockchain.utxos) { + // System.out.println("UTXO ID: " + utxo); + // } + + //TODO : S'asurer de créer une bonne transaction avec les UTxO etc... + //TODO : Faire la signature de la transaction + // + + // Set<Wallet> wallets = new HashSet<Wallet>() { + // { + // add(bobWallet); + // add(aliceWallet); + // } + // }; + // // Création de la blockchain + + + // // MinageManager minageManager = new MinageManager(blockchain); + // // minageManager.mineABloc(); } } diff --git a/src/main/java/fr/miage/Bloc.java b/src/main/java/fr/miage/Bloc.java index 2e47b1b45b3f072159914130454d220b8f038a3c..00e64ee2fabb2e93597ba8f24ae55ccc2ad9cbbb 100644 --- a/src/main/java/fr/miage/Bloc.java +++ b/src/main/java/fr/miage/Bloc.java @@ -50,8 +50,9 @@ public class Bloc { List<Transaction> transactions = new ArrayList<Transaction>(); for (Wallet wallet : wallets) { int amount = RandomNumberGenerator.getRandomNumber(1, 20); - UTxO utxo = new UTxO(null, amount); + UTxO utxo = new UTxO(null, amount); wallet.addUTxO(utxo); + Blockchain.utxos.add(utxo); List<UTxO> utxos = new ArrayList<UTxO>() { { add(utxo); diff --git a/src/main/java/fr/miage/Blockchain.java b/src/main/java/fr/miage/Blockchain.java old mode 100644 new mode 100755 index 180bf59c037d0bafa3c79733822569aa8b100e1e..8accd917ecd4946073a443744a98e604fc2d1ff6 --- a/src/main/java/fr/miage/Blockchain.java +++ b/src/main/java/fr/miage/Blockchain.java @@ -1,12 +1,17 @@ package fr.miage; +import java.util.HashSet; import java.util.LinkedList; +import java.util.List; +import java.util.Random; import java.util.Set; public class Blockchain { private String name; private LinkedList<Bloc> blocs; private Set<Wallet> wallets; + public static Set<UTxO> utxos = new HashSet<>(); + public Set<Transaction> transactionsPool = new HashSet<>(); public Blockchain(String name, Set<Wallet> wallets) { this.name = name; @@ -17,6 +22,37 @@ public class Blockchain { add(Bloc.createGenuineBloc(wallets)); } }; + ; + } + + //Permet de créer une transaction avec deux wallets aléatoire et de l'ajouter dans la transaction pool; + public void createTrasaction(){ + //Random wallet selection + Set<Wallet> walletsCopy = new HashSet<>(wallets); + + int walletIndexSender = new Random().nextInt(walletsCopy.size()); + Wallet walletSender = selectWallet(walletIndexSender); + walletsCopy.remove(walletSender); + + int walletIndexReceiver = new Random().nextInt(walletsCopy.size()); + Wallet walletReceiver = selectWallet(walletIndexReceiver); + + double amountWalletSender = walletSender.getUtxos().stream().mapToDouble(utxo -> utxo.getMontant()).sum(); + double randomAmountToSend = new Random().nextInt((int) amountWalletSender); + Transaction tx = new Transaction(walletSender, walletReceiver, randomAmountToSend, EnumTypeTransaction.NORMAL); + this.transactionsPool.add(tx); + } + + public Wallet selectWallet(int index){ + int i = 0; + for (Wallet wallet : wallets) { + if(i == index){ + return wallet; + } + i++; + } + return null; + } public void addBloc(Bloc bloc) { diff --git a/src/main/java/fr/miage/Transaction.java b/src/main/java/fr/miage/Transaction.java old mode 100644 new mode 100755 index 6c6e7b5f26dd2e605de16aa4c3c2d58ad50d7075..e52ca8e455eb1422b73794ea3df8a73474721c38 --- a/src/main/java/fr/miage/Transaction.java +++ b/src/main/java/fr/miage/Transaction.java @@ -1,25 +1,83 @@ package fr.miage; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.UUID; public class Transaction { private UUID id; + private Wallet sender; + private Wallet receiver; private List<UTxO> inputs; private List<UTxO> outputs; - private String signature; private EnumTypeTransaction typeTransaction; public Transaction(List<UTxO> inputs, List<UTxO> outputs, String signature, EnumTypeTransaction typeTransaction) { this.inputs = inputs; this.outputs = outputs; - this.signature = signature; + this.typeTransaction = typeTransaction; + this.id = UUID.randomUUID(); + } + + public Transaction(Wallet sender, Wallet receiver ,double amount, EnumTypeTransaction typeTransaction) { + this.inputs = sender.getUTxOsForTransaction(amount); + if (inputs != null ) { + if(isValidTransaction(inputs)){ + this.sender = sender; + this.receiver = receiver; + this.typeTransaction = typeTransaction.NORMAL; + this.id = UUID.randomUUID(); + UTxO utxoAmount = new UTxO(receiver.getPublicKey(), getTotalAmountUtxoInput(inputs)); // peut etre changr par amout + this.receiver.addUTxO(utxoAmount); + UTxO utxoRest = new UTxO(sender.getPublicKey(), getTotalAmountUtxoInput(inputs) - amount); + this.sender.addUTxO(utxoRest); + this.outputs = Arrays.asList(utxoAmount, utxoRest); + updateSetUtxo(); + } else { + System.err.println("Transaction invalide, utxo absent"); + } + } else { + System.out.println("Solde insuffisant"); + } + } + + public void updateSetUtxo(){ + Blockchain.utxos.clear(); + Blockchain.utxos.addAll(this.outputs); + } + + // public void signTransaction() throws NoSuchAlgorithmException{ + // Signature signature = Signature.getInstance("SHA256withRSA"); + // signature.initSign(sender.getPrivateKey()); + // } + + public double getTotalAmountUtxoInput(List<UTxO> inputs) { + double total = 0; + for (UTxO utxo : inputs) { + total += utxo.getMontant(); + } + return total; + } + + public boolean isValidTransaction( List<UTxO> inputs) { + boolean isValid = true; + for (UTxO utxo : inputs) { + if (!Blockchain.utxos.contains(utxo)) { + isValid = false; + } + } + return isValid; } public UUID getId() { return this.id; } + public void setId(UUID id) { this.id = id; } @@ -32,9 +90,6 @@ public class Transaction { return this.outputs; } - public String getSignature() { - return this.signature; - } public EnumTypeTransaction getTypeTransaction() { return this.typeTransaction; @@ -46,7 +101,6 @@ public class Transaction { " id='" + getId() + "'" + ", inputs='" + getInputs() + "'" + ", outputs='" + getOutputs() + "'" + - ", signature='" + getSignature() + "'" + ", typeTransaction='" + getTypeTransaction() + "'" + "}"; } diff --git a/src/main/java/fr/miage/UTxO.java b/src/main/java/fr/miage/UTxO.java old mode 100644 new mode 100755 index d1510884f4d98ac4c6e74b0098d6aafd594ca6d6..fbdf1e6d2aea4afd56b0ffa1fa38d9fed04f0401 --- a/src/main/java/fr/miage/UTxO.java +++ b/src/main/java/fr/miage/UTxO.java @@ -2,30 +2,41 @@ package fr.miage; import java.util.UUID; -public class UTxO { +public class UTxO implements Comparable { //UTXO : Hash qui renvoie a la transaction d'avant - private UUID uuid; - private Transaction transaction; // transaction précédente (provenance de l'argent) --> peut etre meme que le hash de la transaction + private UUID uuid; // identifiant + private String transactionHash; // transaction de provenance de l'Utxo (provenance de l'argent) --> peut etre meme que le hash de la transaction private double montant; - public UTxO(Transaction transaction, double montant) { - this.transaction = transaction; + public UTxO(String transactionHash, double montant) { + this.transactionHash = transactionHash; this.montant = montant; } - public Transaction getTransaction() { - return this.transaction; + public String getTransaction() { + return this.transactionHash; } public double getMontant() { return this.montant; } + + @Override public String toString() { - return "{" + - "transaction='" + getTransaction() + "'" + - ", montant='" + getMontant() + "'" + - "}"; + return "UTxO [uuid=" + uuid + ", transactionHash=" + transactionHash + ", montant=" + montant + "]"; + } + + @Override + public int compareTo(Object o) { + UTxO utxo = (UTxO) o; + if (this.montant > utxo.getMontant()) { + return 1; + } else if (this.montant < utxo.getMontant()) { + return -1; + } else { + return 0; + } } } diff --git a/src/main/java/fr/miage/Wallet.java b/src/main/java/fr/miage/Wallet.java index cf65318e644f88d4931f63b6041a41c062165c12..9beca0ffd552fa1a8429494bfb5e0c9ad61f2f10 100644 --- a/src/main/java/fr/miage/Wallet.java +++ b/src/main/java/fr/miage/Wallet.java @@ -1,9 +1,13 @@ package fr.miage; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class Wallet { @@ -12,14 +16,50 @@ public class Wallet { private double solde; private List<UTxO> utxos; - public Wallet(String publicKey, String privateKey) { - this.publicKey = publicKey; + public Wallet(String privateKey, String name) throws NoSuchAlgorithmException, InterruptedException { this.privateKey = privateKey; + initWallet(); + createKeyPair(privateKey, name); + } + + public void initWallet() throws NoSuchAlgorithmException { + this.publicKey = hashSha256(this.privateKey); this.utxos = new ArrayList<>(); } - public void initWallet(byte[] data) throws NoSuchAlgorithmException { + public void createKeyPair(String privateKey, String name) throws InterruptedException{ + + String command = "keytool -genkeypair -alias wallet_"+name+" -keyalg RSA -keysize 2048 -dname \"CN=" + name + "\" -validity 365 -storetype JKS -keystore keystore.jks -storepass \"" + privateKey + "\""; + + System.out.println(command); + ProcessBuilder processBuilder = new ProcessBuilder(command.split("\\s+")); + processBuilder.redirectErrorStream(true); + try { + Process process = processBuilder.start(); + OutputStream outputStream = process.getOutputStream(); + outputStream.write("\n".getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + outputStream.close(); + + InputStream inputStream = process.getInputStream(); + InputStream errorStream = process.getErrorStream(); + byte[] buffer = new byte[1024]; + int bytesRead; + + while ((bytesRead = inputStream.read(buffer)) != -1) { + System.out.write(buffer, 0, bytesRead); + } + + while ((bytesRead = errorStream.read(buffer)) != -1) { + System.err.write(buffer, 0, bytesRead); + + } + } catch (IOException e) { + e.printStackTrace(); + System.out.println("Erreur lors de la création du keypair"); + } + System.out.println("Le wallet de " + name + " a été créé avec succès"); } private String hashSha256(String privateKey) throws NoSuchAlgorithmException { @@ -28,6 +68,27 @@ public class Wallet { return new String(hash, StandardCharsets.UTF_8); } + public List<UTxO> getUTxOsForTransaction(double amount) { + List<UTxO> result = new ArrayList<>(); + int res = 0; + boolean stop = false; + Collections.sort(this.utxos); + for (UTxO utxo : this.utxos) { + if(res >= amount) { + stop = true; + } + if (res < amount && !stop) { + result.add(utxo); + res += utxo.getMontant(); + } + } + if (res < amount) { + return null; + } else { + return result; + } + } + public String getPublicKey() { return this.publicKey; } diff --git a/target/classes/fr/miage/App.class b/target/classes/fr/miage/App.class index e101c779abed4e7b739e1fa70d480be8175b415c..e1089d23ed730878e852d327dc5414686a9f68fc 100644 Binary files a/target/classes/fr/miage/App.class and b/target/classes/fr/miage/App.class differ