117 lines
3.2 KiB
Swift
117 lines
3.2 KiB
Swift
//
|
|
// Block.swift
|
|
// Blockchain
|
|
//
|
|
// Created by Victor BODINAUD on 27/02/2020.
|
|
// Copyright © 2020 Victor BODINAUD. All rights reserved.
|
|
//
|
|
|
|
internal import CryptoSwift
|
|
import Foundation
|
|
|
|
public class Block: Codable {
|
|
var hash: String
|
|
var transactions: [Transaction]
|
|
var previousHash: String
|
|
var index: Int
|
|
var nonce: Int
|
|
var timestamp: Int
|
|
var difficulty: Int
|
|
var miner: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case hash, transactions, previousHash, index, nonce, timestamp, difficulty, miner
|
|
}
|
|
|
|
init(hash: String = "", transactions: [Transaction] = [], previousHash: String = "",
|
|
index: Int = 0, nonce: Int = 0, timestamp: Int = 0, difficulty: Int = 4)
|
|
{
|
|
self.hash = hash
|
|
self.transactions = transactions
|
|
self.previousHash = previousHash
|
|
self.index = index
|
|
self.nonce = nonce
|
|
self.timestamp = timestamp
|
|
self.difficulty = difficulty
|
|
}
|
|
|
|
func mineBlock() -> Double {
|
|
let startTime = Date()
|
|
let target = String(repeating: "0", count: difficulty)
|
|
|
|
print("Mining block \(index) with difficulty \(difficulty)...")
|
|
|
|
repeat {
|
|
nonce += 1
|
|
hash = generateHash()
|
|
} while !hash.hasPrefix(target)
|
|
|
|
let timeElapsed = Date().timeIntervalSince(startTime)
|
|
print("Block mined! Nonce: \(nonce), Hash: \(hash)")
|
|
|
|
return timeElapsed
|
|
}
|
|
|
|
func isValid() -> Bool {
|
|
// Vérification de base du hash
|
|
let target = String(repeating: "0", count: difficulty)
|
|
if hash != generateHash() || !hash.hasPrefix(target) {
|
|
print("Block \(index): Invalid hash")
|
|
return false
|
|
}
|
|
|
|
// Vérifier l'index
|
|
if index < 0 {
|
|
print("Block: Invalid index")
|
|
return false
|
|
}
|
|
|
|
// Vérifier le timestamp
|
|
let currentTime = Int(Date().timeIntervalSince1970)
|
|
if timestamp > currentTime + 7200 || timestamp < 1701388800 { // 2h dans le futur max
|
|
print("Block: Invalid timestamp")
|
|
return false
|
|
}
|
|
|
|
// Vérifier les transactions
|
|
for transaction in transactions {
|
|
if !transaction.isValid() {
|
|
print("Block: Invalid transaction found")
|
|
return false
|
|
}
|
|
|
|
// Vérifier qu'il n'y a qu'une seule récompense de minage
|
|
if transaction.type == "MINING_REWARD" {
|
|
if transactions.filter({ $0.type == "MINING_REWARD" }).count > 1 {
|
|
print("Block: Multiple mining rewards found")
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func generateHash() -> String {
|
|
let txData = transactions.map {
|
|
"\($0.sender)\($0.receiver)\($0.amount)\($0.type)"
|
|
}.joined()
|
|
|
|
return "\(previousHash)\(txData)\(String(timestamp))\(String(index))\(String(nonce))".sha256()
|
|
}
|
|
}
|
|
|
|
// Structure pour suivre la progression du mining
|
|
struct MiningProgress {
|
|
let hashesChecked: Int
|
|
let hashRate: Double
|
|
let elapsedTime: TimeInterval
|
|
let estimatedTimeRemaining: TimeInterval?
|
|
}
|
|
|
|
// Erreurs possibles pendant le mining
|
|
enum MiningError: Error {
|
|
case cancelled
|
|
case failed(String)
|
|
}
|