diff --git a/SwiftChain/main.swift b/SwiftChain/main.swift index 51300a0..ccca6a4 100644 --- a/SwiftChain/main.swift +++ b/SwiftChain/main.swift @@ -45,12 +45,12 @@ Node actif: \(activeNodeName) """) repeat { - print("\nEntrer une commande:") + LogManager.log("\nEntrer une commande:", level: .info) command = readLine()?.lowercased() switch command { case "connect": - print("Entrez l'adresse du pair (ex: 192.168.1.100):") + LogManager.log("Entrez l'adresse du pair (ex: 192.168.1.100):", level: .info) if let host = readLine() { activeNode.connectToPeer(host: host) } @@ -60,69 +60,69 @@ repeat { case "mine": if let _ = activeNode.mineBlock(minerAddress: currentMinerAddress) { - print("Bloc miné avec succès. Récompense envoyée à \(currentMinerAddress)") - print("Nouveau solde: \(activeNode.getBalance(currentMinerAddress))") + LogManager.log("Bloc miné avec succès. Récompense envoyée à \(currentMinerAddress)", level: .success) + LogManager.log("Nouveau solde: \(activeNode.getBalance(currentMinerAddress))", level: .info) } else { - print("Échec du minage") + LogManager.log("Échec du minage", level: .error) } case "balance": - print("Entrer l'adresse:") + LogManager.log("Entrer l'adresse:", level: .info) if let address = readLine() { let balance = activeNode.getBalance(address) - print("Solde de \(address): \(balance)") + LogManager.log("Solde de \(address): \(balance)", level: .info) } case "setminer": - print("Nouvelle adresse du mineur:") + LogManager.log("Nouvelle adresse du mineur:", level: .info) if let address = readLine() { currentMinerAddress = address - print("Adresse du mineur mise à jour: \(currentMinerAddress)") + LogManager.log("Adresse du mineur mise à jour: \(currentMinerAddress)", level: .success) } case "pending": let transactions = activeNode.getPendingTransactions() - print("Transactions en attente: \(transactions.count)") + LogManager.log("Transactions en attente: \(transactions.count)", level: .info) for (index, tx) in transactions.enumerated() { - print(""" + LogManager.log(""" \(index + 1). De: \(tx.sender) À: \(tx.receiver) Montant: \(tx.amount) Type: \(tx.type) - """) + """, level: .info) } case "validity": let isValid = activeNode.isChainValid() - print("Chaîne valide: \(isValid)") + LogManager.log("Chaîne valide: \(isValid)", level: .success) case "exit": - print("Au revoir!") + LogManager.log("Au revoir!", level: .info) case "createwallet": let wallet = Wallet() wallets[wallet.address] = wallet - print("Nouveau wallet créé!") - print("Adresse: \(wallet.address)") + LogManager.log("Nouveau wallet créé!", level: .success) + LogManager.log("Adresse: \(wallet.address)", level: .success) case "listwallet": - print("\nWallets disponibles:") + LogManager.log("\nWallets disponibles:", level: .info) for (address, _) in wallets { - print("- \(address) (Solde: \(activeNode.getBalance(address)))") + LogManager.log("- \(address) (Solde: \(activeNode.getBalance(address)))", level: .info) } case "send": - print("Votre adresse (wallet):") + LogManager.log("Votre adresse (wallet):", level: .info) guard let senderAddress = readLine(), let wallet = wallets[senderAddress] else { - print("Wallet non trouvé") + LogManager.log("Wallet non trouvé", level: .error) break } - print("Adresse du destinataire:") + LogManager.log("Adresse du destinataire:", level: .info) guard let receiverAddress = readLine() else { - print("Adresse du destinataire invalide") + LogManager.log("Adresse du destinataire invalide", level: .error) break } @@ -131,7 +131,7 @@ repeat { let amount = Int(amountStr), amount > 0 else { - print("Montant invalide") + LogManager.log("Montant invalide", level: .error) break } @@ -146,12 +146,12 @@ repeat { if let signature = wallet.signTransaction(transaction) { transaction.signature = signature if activeNode.submitTransaction(transaction) { - print("Transaction signée et propagée au réseau!") + LogManager.log("Transaction signée et propagée au réseau!", level: .success) } else { - print("Erreur lors de l'envoi de la transaction") + LogManager.log("Erreur lors de l'envoi de la transaction", level: .error) } } else { - print("Erreur lors de la signature de la transaction") + LogManager.log("Erreur lors de la signature de la transaction", level: .error) } case "mempool": @@ -165,10 +165,10 @@ repeat { activeNode = node1 activeNodeName = "Node 1" } - print("Node actif: \(activeNodeName)") + LogManager.log("Node actif: \(activeNodeName)", level: .info) default: - print("Commande inconnue") + LogManager.log("Commande inconnue", level: .error) } } while command != "exit" diff --git a/SwiftChainCore/Models/LogManager.swift b/SwiftChainCore/Models/LogManager.swift new file mode 100644 index 0000000..36464a8 --- /dev/null +++ b/SwiftChainCore/Models/LogManager.swift @@ -0,0 +1,38 @@ +// +// LogManager.swift +// SwiftChain +// +// Created by Victor on 05/05/2025. +// + +import os.log + +public struct LogManager { + public enum LogLevel: String { + case info = "INFO" + case success = "SUCCÈS" + case warning = "ATTENTION" + case error = "ERREUR" + case network = "RÉSEAU" + case blockchain = "BLOCKCHAIN" + + var logType: OSLogType { + switch self { + case .info, .success: return .info + case .warning: return .debug + case .error: return .error + case .network, .blockchain: return .default + } + } + } + + static let log = OSLog(subsystem: "com.votreapp.swiftchain", category: "blockchain") + + public static func log(_ message: String, level: LogLevel) { + os_log("%{public}@: %{public}@", log: log, type: level.logType, level.rawValue, message) + + // Également afficher dans la console pour le CLI + let timestamp = DateFormatter.localizedString(from: Date(), dateStyle: .none, timeStyle: .medium) + print("[\(timestamp)] [\(level.rawValue)] \(message)") + } +} diff --git a/SwiftChainCore/Models/Node.swift b/SwiftChainCore/Models/Node.swift index 7342af5..7d60292 100644 --- a/SwiftChainCore/Models/Node.swift +++ b/SwiftChainCore/Models/Node.swift @@ -9,6 +9,9 @@ import Foundation import Network public class Node { + private let nodeId = UUID().uuidString // Identifiant unique pour chaque nœud + private var processedMessages = Set() // Pour traquer les messages déjà traités + // Network properties private var peers: [NWConnection] = [] private var port: NWEndpoint.Port @@ -38,6 +41,15 @@ public class Node { struct NetworkMessage: Codable { let type: MessageType let data: Data + let senderId: String // Identifiant du nœud émetteur + let messageId: String // Identifiant unique du message + + init(type: MessageType, data: Data, senderId: String) { + self.type = type + self.data = data + self.senderId = senderId + self.messageId = UUID().uuidString + } } // Configuration du listener @@ -178,7 +190,7 @@ public class Node { func broadcastTransaction(_ transaction: Transaction) { do { let transactionData = try JSONEncoder().encode(transaction) - let message = NetworkMessage(type: .transaction, data: transactionData) + let message = NetworkMessage(type: .transaction, data: transactionData, senderId: nodeId) let messageData = try JSONEncoder().encode(message) print("Broadcasting transaction to \(peers.count) peers") @@ -220,6 +232,15 @@ public class Node { let message = try JSONDecoder().decode(NetworkMessage.self, from: data) print("Message decoded successfully, type: \(message.type)") + // Vérifier si le message a déjà été traité + if processedMessages.contains(message.messageId) { + print("Message déjà traité, ignoré") + return + } + + // Ajouter le message à la liste des messages traités + processedMessages.insert(message.messageId) + switch message.type { case .transaction: let transaction = try JSONDecoder().decode(Transaction.self, from: message.data) @@ -261,7 +282,7 @@ public class Node { private func requestBlockchain(from peer: NWConnection) { do { - let message = NetworkMessage(type: .blockchainRequest, data: Data()) + let message = NetworkMessage(type: .blockchainRequest, data: Data(), senderId: nodeId) let messageData = try JSONEncoder().encode(message) peer.send(content: messageData, completion: .contentProcessed { error in @@ -279,7 +300,7 @@ public class Node { private func sendBlockchain(to peer: NWConnection) { do { let chainData = try JSONEncoder().encode(blockchain.chain) - let message = NetworkMessage(type: .blockchainResponse, data: chainData) + let message = NetworkMessage(type: .blockchainResponse, data: chainData, senderId: nodeId) let messageData = try JSONEncoder().encode(message) peer.send(content: messageData, completion: .contentProcessed { error in @@ -331,6 +352,11 @@ public class Node { private func handleReceivedBlock(_ block: Block) { print("Received new block: \(block.hash)") + if blockchain.chain.contains(where: { $0.hash == block.hash }) { + print("Bloc déjà dans la chaîne") + return + } + // Vérifier que le bloc suit bien notre dernier bloc guard let lastBlock = blockchain.chain.last else { print("No existing chain") @@ -338,7 +364,13 @@ public class Node { } if block.previousHash != lastBlock.hash { - print("Block does not connect to our chain") + print("Le bloc ne se connecte pas à notre chaîne") + + // Demander la chaîne complète aux pairs pour se synchroniser + for peer in peers { + requestBlockchain(from: peer) + } + return } @@ -367,7 +399,7 @@ public class Node { private func broadcastBlock(_ block: Block) { do { let blockData = try JSONEncoder().encode(block) - let message = NetworkMessage(type: .newBlock, data: blockData) + let message = NetworkMessage(type: .newBlock, data: blockData, senderId: nodeId) let messageData = try JSONEncoder().encode(message) print("Broadcasting block to peers")