The document describes code for implementing a basic blockchain with cryptocurrency functionality in Java. It includes classes for wallets, transactions, blocks, and the overall blockchain data structure. Key points include:
- The Wallet class stores a public/private key pair to manage funds and allow signing of transactions.
- Transactions contain inputs (referencing previous transaction outputs), outputs, and a signature and transfer funds between wallets.
- Blocks contain a list of transactions, hash/nonce fields for proof of work mining, and methods for adding/verifying transactions.
- The Blockchain class manages the full chain of blocks and unspent transaction outputs (UTXOs).
The document describes code for implementing a basic blockchain with cryptocurrency functionality in Java. It includes classes for wallets, transactions, blocks, and the overall blockchain data structure. Key points include:
- The Wallet class stores a public/private key pair to manage funds and allow signing of transactions.
- Transactions contain inputs (referencing previous transaction outputs), outputs, and a signature and transfer funds between wallets.
- Blocks contain a list of transactions, hash/nonce fields for proof of work mining, and methods for adding/verifying transactions.
- The Blockchain class manages the full chain of blocks and unspent transaction outputs (UTXOs).
public void generateKeyPair() { try { KeyPairGenerator keyGen =
KeyPairGenerator.getInstance("ECDSA", "BC"); SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); ECGenParameterSpec ecSpec = new ECGenParameterSpec("prime192v1"); keyGen.initialize(ecSpec, random); KeyPair keyPair = keyGen.generateKeyPair(); // on récupère les clés générées pour notre Wallet privateKey = keyPair.getPrivate(); publicKey = keyPair.getPublic(); } catch (Exception e) { throw new RuntimeException(e); } }
import java.security.PrivateKey;import java.security.PublicKey;import java.util.ArrayList;public class
Transaction { public String transactionId; public PublicKey sender; public PublicKey recipient; public float value; public byte[] signature; public ArrayList<TransactionInput> inputs = new ArrayList<TransactionInput>(); public ArrayList<TransactionOutput> outputs = new ArrayList<TransactionOutput>(); // Nombre de transactions générées private static int sequence = 0; public Transaction(PublicKey from, PublicKey to, float value, ArrayList<TransactionInput> inputs) { this.sender = from; this.recipient = to; this.value = value; this.inputs = inputs; } // ... }
public class Transaction { // ... public boolean processTransaction() { if (verifiySignature() == false) {
System.out.println("Echec de vérification de la signature de la Transaction"); return false; } // On associe les données des transactions entrantes for (TransactionInput i : inputs) { i.UTXO = Blockchain.UTXOs.get(i.transactionOutputId); } // On vérifie que la transaction est valide if (getInputsValue() < Blockchain.minimumTransaction) { System.out.println("Somme montant des transactions entrantes trop faible : " + getInputsValue()); System.out.println("Le montant doit être plus grand que : " + Blockchain.minimumTransaction); return false; } // Génération des transactions sortantes // Calcul montant restant float leftOver = getInputsValue() - value; transactionId = calulateHash(); // prise en compte envoi du montant au destinataire outputs.add(new TransactionOutput(this.recipient, value, transactionId)); // prise en compte montant restant pour l'expéditeur outputs.add(new TransactionOutput(this.sender, leftOver, transactionId)); // Ajout aux transactions non dépensées de la Blockchain for (TransactionOutput o : outputs) { Blockchain.UTXOs.put(o.id, o); } // Suppression de ces transactions de la liste UTXOs de la Blockchain for (TransactionInput i : inputs) { if (i.UTXO == null) continue; Blockchain.UTXOs.remove(i.UTXO.id); } return true; } public float getInputsValue() { float total = 0; for (TransactionInput i : inputs) { if (i.UTXO == null) continue; total += i.UTXO.value; } return total; } // ... } public class Wallet { // ... // Retourne le montant disponible dans le Wallet public float getBalance() { float total = 0; for (Map.Entry<String, TransactionOutput> item : Blockchain.UTXOs.entrySet()) { TransactionOutput UTXO = item.getValue(); if (UTXO.isMine(publicKey)) { // on ajoute uniquement le montant des transactions appartenant à ce wallet UTXOs.put(UTXO.id, UTXO); total += UTXO.value; } } return total; } public Transaction sendFunds(PublicKey recipient, float value) { if (getBalance() < value) { System.out.println("Manque de fonds pour créer la transaction"); return null; } ArrayList<TransactionInput> inputs = new ArrayList<TransactionInput>(); float total = 0; for (Map.Entry<String, TransactionOutput> item : UTXOs.entrySet()) { TransactionOutput UTXO = item.getValue(); total += UTXO.value; inputs.add(new TransactionInput(UTXO.id)); if (total > value) break; } Transaction newTransaction = new Transaction(publicKey, recipient, value, inputs); newTransaction.generateSignature(privateKey); for (TransactionInput input : inputs) { UTXOs.remove(input.transactionOutputId); } return newTransaction; } }
public static String getMerkleRoot(ArrayList<Transaction> transactions) { int count =
transactions.size(); ArrayList<String> previousTreeLayer = new ArrayList<String>(); for (Transaction transaction : transactions) { previousTreeLayer.add(transaction.transactionId); } ArrayList<String> treeLayer = previousTreeLayer; while (count > 1) { treeLayer = new ArrayList<String>(); for (int i = 1; i < previousTreeLayer.size(); i++) { treeLayer.add(applySha256(previousTreeLayer.get(i - 1) + previousTreeLayer.get(i))); } count = treeLayer.size(); previousTreeLayer = treeLayer; } String merkleRoot = (treeLayer.size() == 1) ? treeLayer.get(0) : ""; return merkleRoot; }
public class Block { // ... public ArrayList<Transaction> transactions = new ArrayList<Transaction>();
// ... public void mineBlock(int difficulty) { String merkleRoot = Utils.getMerkleRoot(transactions); data = (!"".equals(merkleRoot)) ? merkleRoot : data; nonce = 0; while (!getHash().substring(0, difficulty).equals(Utils.zeros(difficulty))) { nonce++; hash = Block.calculateHash(this); } } public boolean addTransaction(Transaction transaction) { if (transaction == null) return false; if (previousHash != null) { if (!transaction.processTransaction()) { System.out.println("Transaction non valide. Ajout annulé"); return false; } } transactions.add(transaction); System.out.println("Transaction ajoutée avec succès au bloc"); return true; } }
java.util.List;public class Blockchain { public static float minimumTransaction = 0.1f; private int difficulty; private List<Block> blocks; public static HashMap<String, TransactionOutput> UTXOs = new HashMap<String, TransactionOutput>(); public Wallet walletA; public Wallet walletB; public Transaction genesisTransaction; public Blockchain(int difficulty) { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); // Création des Wallets walletA = new Wallet(); walletB = new Wallet(); Wallet baseWallet = new Wallet(); // Transaction genèse genesisTransaction = new Transaction(baseWallet.publicKey, walletA.publicKey, 100f, null); // Signature de de la transaction genesisTransaction.generateSignature(baseWallet.privateKey); genesisTransaction.transactionId = "0"; genesisTransaction.outputs.add(new TransactionOutput(genesisTransaction.recipient, genesisTransaction.value, genesisTransaction.transactionId)); // Ajout à la liste UTXOs des transactions non dépensées UTXOs.put(genesisTransaction.outputs.get(0).id, genesisTransaction.outputs.get(0)); this.difficulty = difficulty; blocks = new ArrayList<>(); // Création du bloc genèse Block b = new Block(0, System.currentTimeMillis(), null, "Genesis Block"); b.transactions.add(genesisTransaction); b.mineBlock(difficulty); // Ajout du Bloc addBlock(b); } // ... }
public static void main(String[] args) { Blockchain blockchain = new Blockchain(4);
System.out.println("\nWallet A montant : " + blockchain.walletA.getBalance()); System.out.println("Wallet A essaie d'envoyer 40 au Wallet B ..."); Block b = blockchain.newBlock("Block 2"); b.addTransaction(blockchain.walletA.sendFunds(blockchain.walletB.publicKey, 40f)); blockchain.addBlock(b); System.out.println("Wallet A montant : " + blockchain.walletA.getBalance()); System.out.println("Wallet B montant : " + blockchain.walletB.getBalance()); System.out.println("\nWallet A essaie d'envoyer plus (100) que ce qu'il possède ..."); b = blockchain.newBlock("Block 3"); b.addTransaction(blockchain.walletA.sendFunds(blockchain.walletB.publicKey, 1000f)); blockchain.addBlock(b); System.out.println("Wallet A montant : " + blockchain.walletA.getBalance()); System.out.println("Wallet B montant : " + blockchain.walletB.getBalance()); System.out.println("\nWallet B essaie d'envoyer 20 au Wallet A ..."); System.out.println("Wallet A essaie d'envoyer 10 au Wallet B ..."); b = blockchain.newBlock("Block 4"); b.addTransaction(blockchain.walletB.sendFunds(blockchain.walletA.publicKey, 20f)); b.addTransaction(blockchain.walletA.sendFunds(blockchain.walletB.publicKey, 10f)); blockchain.addBlock(b); System.out.println("Wallet A montant : " + blockchain.walletA.getBalance()); System.out.println("Wallet B montant : " + blockchain.walletB.getBalance()); System.out.println(); System.out.println(blockchain); System.out.println("Blockchain valide : " + (blockchain.isBlockChainValid() ? "Oui" : "Non")); }
Get (Ebook) Cryptography: Algorithms, Protocols, and Standards for Computer Security by Zoubir Mammeri ISBN 9781394207480, 1394207484 free all chapters