前言
區(qū)塊鏈(Blockchain)是比特幣等流行的加密貨幣背后的技術(shù)。區(qū)塊鏈的主要概念是去中心化,提供分布式賬本。本文會(huì)為你展示如何在 iOS/macOS 中使用 Swift 語言創(chuàng)建最基本的區(qū)塊鏈。
注意:本文不涉及節(jié)點(diǎn)(nodes/peers)、驗(yàn)證和獎(jiǎng)勵(lì)等。
實(shí)現(xiàn)區(qū)塊類
實(shí)現(xiàn)區(qū)塊類,生成對(duì)象代表一個(gè)區(qū)塊,創(chuàng)建如下:
//MARK: 區(qū)塊
/// 簡單模擬區(qū)塊鏈,假設(shè)是單鏈的
class Block{
var index : Int = 0 //區(qū)塊所在節(jié)點(diǎn)
var dateCreated : String? //區(qū)塊產(chǎn)生時(shí)間
var previousHash : String? //前一個(gè)區(qū)塊的hash
var hash:String? //hash值
var nonce:Int = 0 //生成符合條件的hash值所需次數(shù) -> 模擬難度值
//模擬操作,保證key有值
var key: String {
get {
return String(self.index)+self.dateCreated! + self.previousHash!+String(self.nonce)
}
}
init() {
self.dateCreated = Date().toString()
self.nonce = 0
}
}
實(shí)現(xiàn)區(qū)塊鏈類
生成對(duì)象代表一個(gè)區(qū)塊鏈,這個(gè)區(qū)塊鏈需要一個(gè)區(qū)塊來初始化自己,這個(gè)區(qū)塊,成為創(chuàng)世塊. 代碼如下:
//MARK:- 區(qū)塊鏈,假設(shè)是單鏈的(實(shí)際區(qū)塊鏈要復(fù)雜的多)
class BlockChain {
private (set)var blocks = [Block]()
/// 初始化區(qū)塊鏈
///
/// - Parameter genesisiBlock: 區(qū)塊
init(genesisiBlock:Block) {
//添加區(qū)塊到區(qū)塊鏈中
addBlock(block: genesisiBlock)
}
/// 添加區(qū)塊
///
/// - Parameter block: 區(qū)塊
func addBlock(block:Block) {
if blocks.isEmpty {
//添加創(chuàng)世塊
//第一個(gè)區(qū)塊沒有hash
block.previousHash = "0"
block.hash = generateHash(block: block)
}else{
let previousBlock = getPreviousBlock()
block.previousHash = previousBlock.hash
block.index = blocks.count
block.hash = generateHash(block: block)
}
blocks.append(block)
displayBlock(block: block)
}
func getPreviousBlock() -> Block {
return blocks[blocks.count-1]
}
func displayBlock(block:Block) {
print("---第\(block.index)個(gè)區(qū)塊")
print("創(chuàng)建日期:\(String(describing: block.dateCreated!))")
print("Nonce:\(block.nonce)")
print("前一個(gè)區(qū)塊的hash值:\(String(describing: block.previousHash!))")
print("hash值:\(String(describing: block.hash!))\n\n\n\n")
}
//計(jì)算hash值
private func generateHash(block:Block) ->String{
//計(jì)算hash
var hash = block.key.sha1Hash()
//篩選算出來的hash值
//假設(shè)限制條件是hash值末尾必須是"00"
while !hash.hasSuffix("00") {
block.nonce += 1
hash = block.key.sha1Hash();
}
return hash;
}
}
generateHash 函數(shù)負(fù)責(zé)生成唯一的哈希值并賦值給區(qū)塊。但并不使用完全隨機(jī)的哈希,而是需要以“00”開頭(模擬增加難度,實(shí)際區(qū)塊鏈,這個(gè)值可能一直不同的區(qū)塊計(jì)算,也是不一樣的)的特定哈希。這個(gè)概念叫做“工作量證明系統(tǒng)”。在實(shí)際中工作量證明系統(tǒng)的解法會(huì)更復(fù)雜,解決的人也會(huì)獲得獎(jiǎng)勵(lì)(可能是額外的比特幣,玩客幣等等,看具體交易平臺(tái))。
核心算法
// MARK: - String 類擴(kuò)展
extension String{
func sha1Hash() -> String {
let task = Process()// OC中的NSTask
//Linux命令
// 執(zhí)行路徑 -> 設(shè)置 shell 腳本參數(shù)
// shasum SHA校驗(yàn)
task.launchPath = "/usr/bin/shasum"
task.arguments = [] //包含的shell語句
let inputPipe = Pipe()
//字符串轉(zhuǎn)化為data寫入文件
inputPipe.fileHandleForWriting.write(self.data(using: .utf8)!)//寫入文件
inputPipe.fileHandleForWriting.closeFile()//保存并關(guān)閉
let outputPipe = Pipe()
task.standardOutput = outputPipe //標(biāo)準(zhǔn)輸出
task.standardInput = inputPipe //標(biāo)準(zhǔn)輸入
task.launch()
let data = outputPipe.fileHandleForReading.readDataToEndOfFile()
let hash = String(data: data, encoding: .utf8)!
return hash.replacingOccurrences(of: " -\n", with: "")
}
}
擴(kuò)展
// MARK: - Date 時(shí)間
extension Date{
/// 獲取當(dāng)前時(shí)間,轉(zhuǎn)化為字符串
///
/// - Returns: 時(shí)間戳
func toString() -> String {
let formatter = DateFormatter();
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return formatter.string(from: self);
}
}
全部源碼可以復(fù)制全部源碼直接粘貼到Mac Playground中,直接運(yùn)行,或者創(chuàng)建Command Line Tool 把代碼粘貼到main.swift文件里面