-
corentinstd authoredcorentinstd authored
Blockchain.java 5.32 KiB
package fr.miage;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import fr.miage.blocs.Bloc;
public class Blockchain {
private static Blockchain instance = null;
private String name;
private LinkedList<Bloc> blocs;
private List<Wallet> wallets;
public static Set<UTxO> utxos = new HashSet<>();
public static Set<Transaction> transactionsPool = new HashSet<>();
private Blockchain(String name) throws NoSuchAlgorithmException, InterruptedException {
this.name = name;
this.wallets = setupWallet();
// Création du premier bloc contenant les transactions de coinbase
this.blocs = new LinkedList<>() {
{
add(Bloc.createGenuineBloc(wallets));
}
};
;
}
public static Blockchain getInstance(String name) throws NoSuchAlgorithmException, InterruptedException {
if (instance == null) {
instance = new Blockchain(name);
}
return instance;
}
public List<Wallet> setupWallet() throws NoSuchAlgorithmException, InterruptedException {
List<Wallet> wallets = new ArrayList<>();
for (int i = 0; i < 20; i++) {
wallets.add(new Wallet("Wallet" + i));
}
return wallets;
}
// Permet de créer une transaction avec deux wallets aléatoire et de l'ajouter
// dans la transaction pool;
public void createTransaction() throws InterruptedException {
List<Wallet> walletsCopy = new ArrayList<>();
walletsCopy.addAll(wallets);
Wallet walletSender = selectWallet(walletsCopy);
walletsCopy.remove(walletSender);
Wallet walletReceiver = selectWallet(walletsCopy);
walletsCopy.remove(walletReceiver);
double amountWalletSender = walletSender.getUtxos().stream().mapToDouble(utxo -> utxo.getMontant()).sum();
double randomAmountToSend = new Random().nextDouble(amountWalletSender);
if (walletSender.getUtxos().isEmpty() || walletReceiver.getUtxos().isEmpty()) {
System.out.println("Wallets vides");
return;
}
System.out.println("[TRANSACTION] --- Création d'une transaction =========================================\n");
System.out.println(" " + walletSender.getName() + " envoie " + randomAmountToSend + " à "
+ walletReceiver.getName() + "\n");
Transaction tx = new Transaction(walletSender, walletReceiver, EnumTypeTransaction.NORMAL);
tx.putUTxO(walletSender, walletReceiver, randomAmountToSend);
Blockchain.utxos.addAll(tx.getOutputs());
Blockchain.utxos.removeAll(tx.getInputs());
String transactionData = getTransactionData(tx);
try {
if (makeFakeSign()) {
Wallet fakeWallet = new Wallet("FakeWallet");
tx.sign(transactionData, fakeWallet.getKeyPair().getPrivate());
} else {
tx.sign(transactionData, walletSender.getKeyPair().getPrivate());
}
System.out.println("[SIGNATURE] --- Signature de la transaction : " + tx.getSignature());
if (tx.verifySignature(transactionData, walletSender.getKeyPair().getPublic())) {
Blockchain.transactionsPool.add(tx);
} else {
System.out.println("[SIGNATURE] --- Signature non valide : TRANSACTION REJETEE");
Blockchain.utxos.removeAll(tx.getOutputs());
Blockchain.utxos.addAll(tx.getInputs());
return;
}
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
e.printStackTrace();
}
}
public String getTransactionData(Transaction tx) {
return tx.getInputs().toString() + tx.getOutputs().toString() + tx.getId();
}
public boolean makeFakeSign() {
int num1 = (int) (Math.random() * 5) + 1;
int num2 = (int) (Math.random() * 5) + 1;
return num1 == num2;
}
public Wallet selectWallet(List<Wallet> wallets) {
if (wallets.size() == 0) {
return null;
}
if (wallets.size() == 1) {
return wallets.get(0);
}
int index = new Random().nextInt(wallets.size());
int i = 0;
for (Wallet wallet : wallets) {
if (i == index) {
return wallet;
}
i++;
}
return null;
}
public void addBloc(Bloc bloc) {
this.blocs.add(bloc);
}
public Bloc getLastBloc() {
return this.blocs.getLast();
}
public String getName() {
return this.name;
}
private LinkedList<Bloc> getBlocs() {
return this.blocs;
}
public List<Wallet> getWallets() {
return this.wallets;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 1; i < this.blocs.size(); i++) {
sb.append("Bloc n° : " + i + this.blocs.get(i).getHash() + "\n");
}
return sb.toString();
}
}