Skip to content
Snippets Groups Projects
Commit 72477f3e authored by BRODIER Jeremy's avatar BRODIER Jeremy
Browse files

Merge branch 'feat/coinbase' into 'main'

Create coinbase and genuine bloc

See merge request !1
parents 30a09594 db42a627
Branches
No related tags found
1 merge request!1Create coinbase and genuine bloc
target/ target/
.vscode .vscode
.idea
\ No newline at end of file
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>
... ...
......
package fr.miage; package fr.miage;
import java.security.NoSuchAlgorithmException; import java.util.HashSet;
import java.util.Set;
/** /**
* Hello world! * Hello world!
...@@ -8,14 +9,23 @@ import java.security.NoSuchAlgorithmException; ...@@ -8,14 +9,23 @@ import java.security.NoSuchAlgorithmException;
*/ */
public class App public class App
{ {
public static void main( String[] args ) throws NoSuchAlgorithmException public static void main( String[] args )
{ {
System.out.println("Début de la blockchain"); System.out.println("Début de la blockchain");
// Création de la blockchain
Blockchain blockchain = new Blockchain("BloBlockchain");
// Création de 2 wallets // Création de 2 wallets
Wallet bobWallet = new Wallet("Ceci est la clé privé de bob"); Wallet bobWallet = new Wallet("publicKey1", "privateKey1");
///System.out.println(bobWallet.getPublicKey()); Wallet aliceWallet = new Wallet("publicKey2", "privateKey2");
//System.out.println(bobWallet.getPrivateKey()); Set<Wallet> wallets = new HashSet<Wallet>() {
{
add(bobWallet);
add(aliceWallet);
}
};
// Création de la blockchain
Blockchain blockchain = new Blockchain("BloBlockchain", wallets);
System.out.println(blockchain);
// MinageManager minageManager = new MinageManager(blockchain);
// minageManager.mineABloc();
} }
} }
package fr.miage; package fr.miage;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.Set;
import org.apache.commons.codec.digest.DigestUtils;
public class Bloc { public class Bloc {
private String hash; private String hash;
private List<Transaction> transactions; private List<Transaction> transactions;
private String header; private String header; // Contient le nonce et le hash du bloc précédent
public Bloc(String hash, List<Transaction> transactions) { public Bloc(String hash, List<Transaction> transactions) {
this.hash = hash; this.hash = hash;
...@@ -16,17 +21,19 @@ public class Bloc { ...@@ -16,17 +21,19 @@ public class Bloc {
public String getHash() { public String getHash() {
return hash; return hash;
} }
public String getHeader() { public String getHeader() {
return header; return header;
} }
public void setHash(String hash) { public void setHash(String hash) {
this.hash = hash; this.hash = hash;
} }
public void setHeader(String header) { public void setHeader(String header) {
this.header = header; this.header = header;
} }
public Bloc(List<Transaction> transactions) { public Bloc(List<Transaction> transactions) {
this.transactions = transactions; this.transactions = transactions;
} }
...@@ -34,7 +41,59 @@ public class Bloc { ...@@ -34,7 +41,59 @@ public class Bloc {
public List<Transaction> getTransactions() { public List<Transaction> getTransactions() {
return transactions; return transactions;
} }
public void setTransactions(List<Transaction> transactions) { public void setTransactions(List<Transaction> transactions) {
this.transactions = transactions; this.transactions = transactions;
} }
public static Bloc createGenuineBloc(Set<Wallet> wallets) {
List<Transaction> transactions = new ArrayList<Transaction>();
for (Wallet wallet : wallets) {
int amount = RandomNumberGenerator.getRandomNumber(1, 20);
UTxO utxo = new UTxO(null, amount);
wallet.addUTxO(utxo);
List<UTxO> utxos = new ArrayList<UTxO>() {
{
add(utxo);
}
};
Coinbase coinbase = new Coinbase(utxos, wallet.getPublicKey(), EnumTypeTransaction.COINBASE);
transactions.add(coinbase);
}
BlocHeader blocHeader = new BlocHeader("", Instant.now().toEpochMilli(), 0);
String header = blocHeader.toString();
String hash = generateHash(header, transactions);
return new Bloc(hash, transactions);
}
private static String generateHash(String header, List<Transaction> transactions) {
return DigestUtils.sha256Hex(header + transactions.toString());
}
public String getTransactionsString() {
StringBuilder sb = new StringBuilder();
for (Transaction transaction : this.transactions) {
sb.append(transaction.toString());
}
return sb.toString();
}
public class RandomNumberGenerator {
public static int getRandomNumber(int min, int max) {
Random random = new Random();
return random.nextInt(max) + min;
}
}
@Override
public String toString() {
return "{" +
" hash='" + getHash() + "'" +
", transactions='" + getTransactions() + "'" +
", header='" + getHeader() + "'" +
"}";
}
} }
// package fr.miage; package fr.miage;
// public class BlocHeader { public class BlocHeader {
// private String previousHash; private String previousHash;
// private long time; private long time;
// private long nonce; private long nonce;
// private long size; // private long size;
// public static final int DIFFICULTY = 27; // public static final int DIFFICULTY = 27;
// public BlocHeader(String hash, String previousHash, long time, long nonce, long size) { public BlocHeader(String previousHash, long time, long nonce) {
// this.hash = hash; // this.hash = hash;
// this.previousHash = previousHash; this.previousHash = previousHash;
// this.time = time; this.time = time;
// this.nonce = nonce; this.nonce = nonce;
// this.size = size; // this.size = size;
// } }
// public String getHash() { // public String getHash() {
// return hash; // return hash;
...@@ -23,25 +23,25 @@ ...@@ -23,25 +23,25 @@
// this.hash = hash; // this.hash = hash;
// } // }
// public String getPreviousHash() { public String getPreviousHash() {
// return previousHash; return previousHash;
// } }
// public void setPreviousHash(String previousHash) { // public void setPreviousHash(String previousHash) {
// this.previousHash = previousHash; // this.previousHash = previousHash;
// } // }
// public long getTime() { public long getTime() {
// return time; return time;
// } }
// public void setTime(long time) { // public void setTime(long time) {
// this.time = time; // this.time = time;
// } // }
// public long getNonce() { public long getNonce() {
// return nonce; return nonce;
// } }
// public void setNonce(long nonce) { // public void setNonce(long nonce) {
// this.nonce = nonce; // this.nonce = nonce;
...@@ -57,4 +57,4 @@ ...@@ -57,4 +57,4 @@
// } }
package fr.miage; package fr.miage;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Set;
public class Blockchain { public class Blockchain {
private String name; private String name;
private LinkedList<Bloc> blocs; private LinkedList<Bloc> blocs;
private Set<Wallet> wallets;
public Blockchain(String name) { public Blockchain(String name, Set<Wallet> wallets) {
this.name = name; this.name = name;
this.blocs = new LinkedList<Bloc>(); this.wallets = wallets;
// Création du premier bloc contenant les transactions de coinbase
this.blocs = new LinkedList<>() {
{
add(Bloc.createGenuineBloc(wallets));
}
};
}
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 Set<Wallet> getWallets() {
return this.wallets;
}
@Override
public String toString() {
return "{" +
" name='" + getName() + "'" +
", blocs='" + getBlocs() + "'" +
", wallets='" + getWallets() + "'" +
"}";
}
} }
package fr.miage;
import java.util.ArrayList;
import java.util.List;
public class Coinbase extends Transaction {
public Coinbase(List<UTxO> inputs, List<UTxO> outputs, String signature, EnumTypeTransaction typeTransaction) {
super(inputs, outputs, signature, EnumTypeTransaction.COINBASE);
}
public Coinbase(List<UTxO> outputs, String signature, EnumTypeTransaction typeTransaction) {
super(new ArrayList<UTxO>(), outputs, signature, EnumTypeTransaction.COINBASE);
}
}
package fr.miage; package fr.miage;
import java.math.BigInteger; import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Optional;
import java.util.stream.DoubleStream; import java.util.stream.DoubleStream;
import javax.swing.text.html.Option;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
public class MinageManager { public class MinageManager {
private static final int DIFFICULTY = 27; private static final int DIFFICULTY = 27;
private Blockchain blockchain;
public MinageManager(Blockchain blockchain) {
this.blockchain = blockchain;
}
public Bloc mineABloc() {
Bloc previousBloc = blockchain.getLastBloc();
return mineABloc(previousBloc);
}
public MinageManager() { public Bloc mineABloc(Bloc previousBloc) {
String header = previousBloc.getHeader();
double target = computeTarget(header);
int nonce = findNonce(header, target);
String hash = DigestUtils.sha256Hex(header + nonce + previousBloc.getTransactionsString());
return new Bloc(hash, previousBloc.getTransactions());
} }
private static double computeTarget(String header) {
return new BigInteger(header, 16).doubleValue() / Math.pow(2, DIFFICULTY);
}
public Bloc mineABloc(Bloc previousBloc) { private static int findNonce(String header, double target) {
double target = Math.pow(2, 256 - DIFFICULTY); return (int) DoubleStream.iterate(0, i -> i + 1).limit((long) Math.pow(2, DIFFICULTY))
//DoubleStream doubleStream = DoubleStream.iterate(0, i -> i + 1).limit((long) Math.pow(2, DIFFICULTY)); .filter(nonce -> new BigInteger(DigestUtils.sha256Hex(header + nonce), 16).doubleValue() < target)
Compute result = new Compute(new BigInteger(DigestUtils.sha256Hex(previousBloc.getHeader() + Math.pow(2,DIFFICULTY)), 16).doubleValue(), Math.pow(2,DIFFICULTY)); .findFirst().orElseThrow();
if(result.hash < target){
System.out.println("Bloc miné avec succès : " + result.nonce);
System.out.println("Hash : " + DigestUtils.sha256Hex(previousBloc.getHeader() + result.nonce));
Bloc bloc = new Bloc(transactions, new BlocHeader(DigestUtils.sha256Hex(previousBloc.getHeader() + result.nonce), previousBloc.getHeader(), System.currentTimeMillis(), result.nonce, transactions.size()));
} }
System.out.println("Failed after " + BlocHeader.DIFFICULTY + " tries");
return new Result("", BlocHeader.DIFFICULTY);
record Result(String hash, double nonce) {
} }
record Result(String hash, double nonce){} record Compute(double hash, double nonce) {
record Compute(double hash, double nonce){} }
} }
package fr.miage; package fr.miage;
import java.util.List; import java.util.List;
import java.util.UUID;
public class Transaction { public class Transaction {
private String id; private UUID id;
private List<UTxO> inputs; private List<UTxO> inputs;
private List<UTxO> outputs; private List<UTxO> outputs;
private String signature; private String signature;
private String typeTransaction; private EnumTypeTransaction typeTransaction;
private Bloc bloc;
public Transaction(String id, List<UTxO> inputs, List<UTxO> outputs, String signature, String typeTransaction) { public Transaction(List<UTxO> inputs, List<UTxO> outputs, String signature, EnumTypeTransaction typeTransaction) {
this.id = id;
this.inputs = inputs; this.inputs = inputs;
this.outputs = outputs; this.outputs = outputs;
this.signature = signature; this.signature = signature;
} }
public void createTransaction(Wallet fromWallet, String toWallet, double amount, List<UTxO> utxoInput, List<UTxO> utxoOutput){ public UUID getId() {
//créer transaction normale return this.id;
this.signature = fromWallet.getPrivateKey(); }
public void setId(UUID id) {
this.id = id;
}
public List<UTxO> getInputs() {
return this.inputs;
} }
public void createFirstTranscation(Wallet fromWallet, String toWallet, double amount, List<UTxO> utxoInput, List<UTxO> utxoOutput){ public List<UTxO> getOutputs() {
//créer transaction normale return this.outputs;
this.signature = fromWallet.getPrivateKey(); }
utxoInput.add(new UTxO(fromWallet, null, amount))
public String getSignature() {
return this.signature;
} }
//créer transaction coinbase public EnumTypeTransaction getTypeTransaction() {
return this.typeTransaction;
}
//un bloc avec que des coinbase avec un seul utxo de sortie @Override
public String toString() {
return "{" +
" id='" + getId() + "'" +
", inputs='" + getInputs() + "'" +
", outputs='" + getOutputs() + "'" +
", signature='" + getSignature() + "'" +
", typeTransaction='" + getTypeTransaction() + "'" +
"}";
}
} }
package fr.miage; package fr.miage;
import java.util.UUID;
public class UTxO { public class UTxO {
//UTXO : Hash qui renvoie a la transaction d'avant //UTXO : Hash qui renvoie a la transaction d'avant
private Wallet hashWallet; // hash du wallet private UUID uuid;
private Transaction transaction; // transaction précédente (provenance de l'argent) --> peut etre meme que le hash de la transaction
private double montant; private double montant;
public UTxO(Wallet hashWallet, Transaction transaction, double montant) { public UTxO(Transaction transaction, double montant) {
this.hashWallet = hashWallet; this.transaction = transaction;
this.montant = montant; this.montant = montant;
} }
public Transaction getTransaction() {
return this.transaction;
}
public double getMontant() {
return this.montant;
}
@Override
public String toString() {
return "{" +
"transaction='" + getTransaction() + "'" +
", montant='" + getMontant() + "'" +
"}";
}
} }
...@@ -3,39 +3,53 @@ package fr.miage; ...@@ -3,39 +3,53 @@ package fr.miage;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Wallet { public class Wallet {
private String publicKey; private String publicKey;
private String privateKey; // pour la signature private String privateKey; // pour la signature
private double solde; private double solde;
private List<UTxO> utxos; private List<UTxO> utxos;
public Wallet(String publicKey, String privateKey) {
public Wallet(String privateKey) throws NoSuchAlgorithmException { this.publicKey = publicKey;
this.init(privateKey); this.privateKey = privateKey;
this.utxos = new ArrayList<>();
} }
public void initWallet(byte[] data) throws NoSuchAlgorithmException {
private void init(String privateKey) throws NoSuchAlgorithmException{ }
private String hashSha256(String privateKey) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256"); MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(privateKey.getBytes(StandardCharsets.UTF_8)); byte[] hash = md.digest(privateKey.getBytes(StandardCharsets.UTF_8));
StringBuilder hashedByte = new StringBuilder(); return new String(hash, StandardCharsets.UTF_8);
for(byte b : hash){
hashedByte.append(String.format("%02x", b));
} }
this.publicKey = hashedByte.toString();
this.privateKey = privateKey; public String getPublicKey() {
this.solde = 20; return this.publicKey;
this.utxos.add(new UTxO(this, null, solde))
} }
public String getPrivateKey() { public String getPrivateKey() {
return privateKey; return this.privateKey;
} }
public String getPublicKey() {
return publicKey; public List<UTxO> getUtxos() {
return this.utxos;
} }
public void addUTxO(UTxO utxo) {
this.utxos.add(utxo);
}
@Override
public String toString() {
return "{" +
" publicKey='" + getPublicKey() + "'" +
", privateKey='" + getPrivateKey() + "'" +
", utxos='" + getUtxos() + "'" +
"}";
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment