Blockchain

如何用 Swift 打造你的第一個區塊鏈 App

區塊鏈 (Blockchain) 是一種突破性技術 (Disruptive Technologies),近年漸獲關注。為什麼呢?因為區塊鏈是許多加密貨幣 (Cryptocurrencies) 如比特幣 (Bitcoin)、以太坊 (Ethereum)、萊特幣 (Litecoin) 的創始技術。那區塊鏈是如何運作的呢?在本次的教學裡,我將會談到所有關於區塊鏈技術的知識,以及如何用 Swift 來製作自己的「區塊鏈」。
如何用 Swift 打造你的第一個區塊鏈 App
如何用 Swift 打造你的第一個區塊鏈 App
In: Blockchain, Swift 程式語言

區塊鏈 (Blockchain) 是一種突破性技術 (Disruptive Technologies),近年漸獲關注。為什麼呢?因為區塊鏈是許多加密貨幣 (Cryptocurrencies) 如比特幣 (Bitcoin)、以太坊 (Ethereum)、萊特幣 (Litecoin) 的創始技術。那區塊鏈是如何運作的呢?在本次的教學裡,我將會談到所有關於區塊鏈技術的知識,以及如何用 Swift 來製作自己的「區塊鏈」。那麼,讓我們開始吧!

區塊鏈的運作

顧名思義,區塊鏈就是一個由不同的區塊串連在一起的「鏈」,每個區塊包含三則資訊:資料 (Data)、雜湊值 (Hash)、和前一個區塊的雜湊值。

  1. 資料 ── 依據使用情境,儲存在區塊的資料會因區塊鏈的類型而不同。例如,在比特幣區塊鏈中,儲存資料就是與交易有關的資訊,即是轉帳的金額、以及參與交易二人的資訊。
  2. 雜湊值 ── 你可以把雜湊想成是一種數位指紋,它是用來識別一個區塊及其資料。雜湊最重要的地方,就是它是一個獨一無二的字母數字 (Alphanumeric) 程式碼,通常會由 64 個字元組成。當一個區塊被創造時,雜湊值也同時產生。當一個區塊被更動時,雜湊值也會同時被更動。透過這種方式,當你想要查看區塊上的任何變動時,雜湊值就非常重要。
  3. 前一個區塊的雜湊值 ── 每個區塊就是藉由儲存前個區塊的雜湊來鏈結在一起,組成一個區塊鏈!這就是讓區塊鏈如此安全的原因。

看看這張圖片:

blockchain-explained

如你所見,每個區塊由資料(未顯示)、雜湊值、和前一個區塊雜湊值所組成。舉個例子,黃色區塊包含了自己的雜湊值 H7S6、和紅色區塊的雜湊值 8SD9。以這種方式,它們組成了一個鏈結,並以此連結在一起。現在,假設有個駭客入侵並嘗試更動紅色區塊。請記住,每次一個區塊以任何方式被更動時,區塊的雜值湊也會被更動!因此,當下一個區塊執行確認、並看到前一個區塊的雜湊值並不吻合時,它會有效地將自己從「鏈」中分離出來,而不會被駭客讀取。

這就是區塊練會如此安全的原因,你幾乎不可能嘗試回溯並更改任何資料。雜湊值提供了不錯的保密及隱私,但還有兩個安全機制來讓區塊鏈更加安全:驗證 (Proof-of-work) 及智慧合約 (Smart Contract)。雖然我不會詳述,但你可以在這裡了解更多。

區塊鏈最後一個保全方式就是基於它的位置。與大多儲存在伺服器或是資料庫內的資料不同,區塊鏈使用點對點網路 (Peer-To-Peer, P2P),它是一種網路型態,允許任何人加入並將該網路上的資料分發給每位接收者。

每當有人加入這個網路時,他們就會得到區塊鏈的完整拷貝;每當有人建立一個新區塊時,就會傳送到網路內的所有人。然後,透過一些複雜的程式,讓節點 (Node) 在加入這個區塊到區塊鏈之前,先確認該區塊有否被竄改。就這樣,任何地方的任何人都可以取得這些資訊。如果你是 HBO 矽谷群瞎傳 (Silicon Valley) 的忠實粉絲,這聽起來可能有點熟悉,因為在這齣美劇裡,主角就是用了類似的技術來建立一個全新網路。

因為每個人或節點都有一份區塊鏈的拷貝,他們可以有共識並確認哪些區塊是合法的。因此,如果你想要駭入一個區塊,你必須駭入網路上超過 50% 的區塊來通過你的資訊。這就是為什麼區塊鏈或許是過去十年以來最安全的技術之一。

關於範例應用

現在你了解區塊鏈是如何運作了,那麼開始來製作我們的範例 App 吧!請先下載初始專案

如你所見,我們有兩個比特幣錢包。第一個帳號 Account 1065 擁有 500 BTC,而第二個帳號 0217 則甚麼都沒有。我們利用傳送按鈕來傳送比特幣到其他帳號。為了賺取 BTC,我們按下 Mine 按鈕就可以獲得 50 BTC 為獎勵。基本來說,我們做的是當 App 執行時,利用控制台來觀察兩個比特幣帳號間的交易情況。

Blockchain demo storyboard

你會注意到,側邊欄裡有兩個重要的類別:BlockBlockchain。打開這些檔案,你會看到檔案是空的,那是因為我將會引導你寫出這些類別的邏輯。那我們開始吧!

在 Swift 定義 Block

前往 Block.swift 並添加程式碼以定義一個區塊。首先,讓我們了解一下區塊是什麼。我們先前定義了一個區塊由三個部分組成: 雜湊值、記錄的實際資料、以及前一個區塊的雜湊值。當我們想建立自己的區塊鏈時,必須要知道區塊的排序,這一點可以很容易地在 Swift 中定義。添加以下程式碼到類別裡:

var hash: String!
var data: String!
var previousHash: String!
var index: Int!

現在,我們需要添加最後一個重要的程式碼。我之前提到每次一個區塊被更動,雜湊就會改變;這就是區塊鏈如此安全的特色之一。所以我們必須建立一個函式來產生一個隨機字母數字的雜湊。這個函式只需要幾行程式碼:

func generateHash() -> String {
    return NSUUID().uuidString.replacingOccurrences(of: "-", with: "")
}

NSUUID 是一個物件,代表橋接 UUID 的通用唯一值。它內置於 Swift 中,而且非常適合用來產生 32 字元的字串。這個函式產生一個 UUID,消除所有連字符 (-),然後回傳 String,即區塊的雜湊。Block.swift 現在應該看起來像這樣:

blockchain-4

我們已經定義了 Block 類別,接著讓我們定義 Blockchain 類別吧。切換到 Blockchain.swift

在 Swift 定義 Blockchain

如前文所說,讓我們嘗試從基本面來了解區塊鏈。在基本的術語裡,區塊鏈只是區塊串在一起組成的鏈;換句話說,它是一個包含所有項目的列表。聽起來是不是有點熟悉呢?因為這就是陣列的定義,而這個陣列就是由區塊所組成!讓我們把下列的程式碼加進去吧:

var chain = [Block]()
小提示:這幾乎可以應用在電腦科學世界的所有事上。如果你曾遇過大問題,試著將它拆解成小組件,然後以自己的方法來解決問題;就像我們弄清楚如何在 Swift 中加入區塊及區塊鏈一樣!

你會注意到在陣列裡面包含了先前定義的 Block 類別,那是我們在區塊鏈中需要的所有變數。加入兩個函式到類別裡,我們就完成了。試著用我前文所教的來回答這個問題:

在一個區塊鏈中,兩個主要的函式是什麼?

希望你能夠回答這個問題!這兩個區塊鏈擁有的主要函式,是用來建立初始區塊,以及在後面新增新的區塊。當然,現在我不會下放這個鏈並加入智慧合約,但是這些是基本函式!加入以下程式碼到 Blockchain.swift

func createGenesisBlock(data:String) {
    let genesisBlock = Block()
    genesisBlock.hash = genesisBlock.generateHash()
    genesisBlock.data = data
    genesisBlock.previousHash = "0000"
    genesisBlock.index = 0
    chain.append(genesisBlock)
}

func createBlock(data:String) {
    let newBlock = Block()
    newBlock.hash = newBlock.generateHash()
    newBlock.data = data
    newBlock.previousHash = chain[chain.count-1].hash
    newBlock.index = chain.count
    chain.append(newBlock)
}
  1. 我們加入的第一個函式是用來建立初始區塊。為此,我們建立了一個函式來把區塊的資料作為 Input。然後,我們定義一個名為genesisBlock 的變數,並將它設為 Block 型別。因為它是 Block 型別,所以它有我們之前在 Block.swift 定義的所有變數及函式。我們設定 generateHash() 為雜湊、 Input data 為資料 。因為這是第一個區塊,所以我們將前一個區塊的雜湊設定為 000,好讓我們知道這是初始區塊。我們將它的索引值設為 0 ,然後放到區塊鏈 chain
  2. 我們建立的下一個函式則適用於所有 genesisBlock 後的區塊,而它會建立剩下的所有區塊。你會注意到它跟之前的函式非常相似,唯一的不同的是我們將 previousHash 設定為前一個區塊的雜湊,並將 index 設為它在區塊練的位置。

完成了!我們已經成功定義自己的 Blockchain!你的程式碼應該如下圖所示!

blockchain-5

接著,我們將所有的部分連接到 ViewController.swift 檔案,並看看執行成果吧!

錢包後台 (Wallet Backend)

切換到 ViewController.swift,我們可以看到所有的 UI 元件都已經連結完畢。我們所需要做的就是處理交易,並將交易列印到控制台上。

然而在開始之前,我們應該稍微探討一下比特幣區塊鏈。比特幣來自一個總帳號,假設這個帳號的編號是 000。當你挖掘一顆比特幣時,就表示你解答了數學問題,並獲得一定數量的比特幣作為獎勵。這是發行貨幣一個很聰明的方法,同時也創造了讓更多人去挖掘的動機。在我們的 App 裡,我們將 100 BTC 作為獎勵。首先,讓我們在 ViewController 添加需要的變數:

let firstAccount = 1065
let secondAccount = 0217
let bitcoinChain = Blockchain()
let reward = 100
var accounts: [String: Int] = ["0000": 10000000]
let invalidAlert = UIAlertController(title: "Invalid Transaction", message: "Please check the details of your transaction as we were unable to process this.", preferredStyle: .alert)

我們定義兩個帳號:一個編號為 1065,另一個編號為 0217。我們同時新增一個 bitcoinChain 變數來作為我們的區塊鏈,並將 reward 設定為 100。我們需要一個作為比特幣來源的主帳號:這是我們的初始帳號,編號為 0000,它擁有一千萬個比特幣。你可以把這個帳號當成銀行,在每一次的獎勵中,就會從中取出 100 個比特幣,並轉至合法的帳號裡。我們也定義一個警告,在每次交易無法完成時顯示。

現在,讓我們來寫些將會執行的泛用函式。你可以猜到這些函式是什麼嗎?

  1. 第一個函式是用來處理交易的。我們要確認傳送者及接收者的帳號中,接收或扣除的金額是正確的,而且這個資訊會被記錄在我們的區塊鏈上。
  2. 下一個函式是要在控制台裡印出完整的紀錄,它會顯示每個區塊及每個區塊內的資料。
  3. 最後一個函式是用來驗證區塊鏈是否合法,方法為確認前個區塊的雜湊是否符合下一個區塊的資訊。因為我們不會示範任何駭客方法,所以範例中的鏈永遠都是合法的。

Transaction 函式

以下是我們的泛用交易函式。在定義變數之下輸入以下程式碼:

func transaction(from: String, to: String, amount: Int, type: String) {
    // 1
    if accounts[from] == nil {
        self.present(invalidAlert, animated: true, completion: nil)
        return
    } else if accounts[from]!-amount < 0 {
        self.present(invalidAlert, animated: true, completion: nil)
        return
    } else {
        accounts.updateValue(accounts[from]!-amount, forKey: from)
    }
    
    // 2
    if accounts[to] == nil {
        accounts.updateValue(amount, forKey: to)
    } else {
        accounts.updateValue(accounts[to]!+amount, forKey: to)
    }
    
    // 3
    if type == "genesis" {
        bitcoinChain.createGenesisBlock(data: "From: \(from); To: \(to); Amount: \(amount)BTC")
    } else if type == "normal" {
        bitcoinChain.createBlock(data: "From: \(from); To: \(to); Amount: \(amount)BTC")
    }
}

看起來程式碼很多,但是它的核心只是為每次的交易定義一些規則。在開頭的地方,我們有四個參數:tofromamount 以及 type。To、From、及 Amount 的含義一目了然,而 Type 基本上就是定義交易的類型。這裡有兩種 Type:Normal 和 Genesis。一個 Normal 的交易類型會是在帳號 10650217 之間進行,而 Genesis 交易類型則會涉及到帳號 0000

  1. 第一個 if-else 條件式是關於來源帳號。如果來源帳號不存在或金額不足,我們會顯示交易無效的警告,然後結束函式。而如果通過的話,我們會更新數值
  2. 第二個 if-else 條件式是關於接收帳號。如果接收帳號不存在,那麼我們隨它而去,然後結束函式。要不然,我們就會傳送正確的比特幣數量到帳號。
  3. 第三個 if-else 條件式處理交易的類型。如果一個交易涉及初始區塊,我們就建立一個新的初始區塊;反之我們建立一個新區塊來儲存資料。

Printing 函式

在每次交易的最後,我們想要看到一個清單列出所有交易,來確保我們知道所有發生的事情。以下是我們在 transaction 函式下輸入的程式碼:

func chainState() {
    for i in 0...bitcoinChain.chain.count-1 {
        print("\tBlock: \(bitcoinChain.chain[i].index!)\n\tHash: \(bitcoinChain.chain[i].hash!)\n\tPreviousHash: \(bitcoinChain.chain[i].previousHash!)\n\tData: \(bitcoinChain.chain[i].data!)")
    }
    redLabel.text = "Balance: \(accounts[String(describing: firstAccount)]!) BTC"
    blueLabel.text = "Balance: \(accounts[String(describing: secondAccount)]!) BTC"
    print(accounts)
    print(chainValidity())
}

這是一個簡單的 for 迴圈,包含 bitcoinChain 的每個區塊。我們印出區塊的編號、雜湊值、前個區塊的雜湊、以及儲存的資料,再更新 UILabel 來顯示每個帳號內正確的 BTC 數目。最後,印出一個列出每個帳號的清單(應該會有三個),並驗證鏈的合法性。

現在,你應該會在函式最後一行中發生錯誤。這是因為我們還沒定義 chainValidity() 函式,那麼就來開始吧!

Validity 函式

記住,如果前一個區塊的雜湊值符合目前區塊所描述的內容,那麼這一個鏈就是合法的。我們可以輕易地用另一個 for 迴圈來重複驗證每個區塊。

func chainValidity() -> String {
    var isChainValid = true
    for i in 1...bitcoinChain.chain.count-1 {
        if bitcoinChain.chain[i].previousHash != bitcoinChain.chain[i-1].hash {
            isChainValid = false
        }
    }
    return "Chain is valid: \(isChainValid)\n"
}

跟之前有點相似,我們在 bitcoinChain 中重複驗證每個區塊,來確認前一個區塊的雜湊值是否與目前區塊所描述的內容符合。

這樣就完成了!我們已經定義了函式,並將會每次都用到它們!你的 ViewController.swift 現在應該看起來像這樣:

blockchain-6

現在我們只需要將按鈕連接到函式就完成了,來開始最後的篇章吧!

將所有東西連結在一起

當我們的 App 首次啟動時,我們想讓初始帳號 0000 傳送 50 BTC 到我們的第一個帳號。然後,我們將讓第一個帳號傳送 10 BTC 到第二個帳號。這個步驟僅需三行程式碼就可以完成。如此更改你的 viewDidLoad 函式:

override func viewDidLoad() {
    super.viewDidLoad()
    transaction(from: "0000", to: "\(firstAccount)", amount: 50, type: "genesis")
    transaction(from: "\(firstAccount)", to: "\(secondAccount)", amount: 10, type: "normal")
    chainState()
    self.invalidAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
}

我們使用先前定義好的函式,並在最後呼叫 chainState()。同時,我們新增一個 OK 按鈕到交易無效的警告中。

現在讓我們來看看剩下的四個函式裡要加入什麼:redMine()blueMine()redSend()blueSend()

挖礦函式

挖礦函式非常地簡單,只要三行程式碼就行了。這就是我們要添加的程式碼:

@IBAction func redMine(_ sender: Any) {
    transaction(from: "0000", to: "\(firstAccount)", amount: 100, type: "normal")
    print("New block mined by: \(firstAccount)")
    chainState()
}
    
@IBAction func blueMine(_ sender: Any) {
    transaction(from: "0000", to: "\(secondAccount)", amount: 100, type: "normal")
    print("New block mined by: \(secondAccount)")
    chainState()
}

在第一個挖礦函式中,我們使用 transaction 函式從初始帳號傳送 100 BTC 到第一個帳號,先印出一個區塊被挖出,再印出 chainState。同樣地,我們在 blueMine 函式裡將 100 BTC 傳送到第二個帳號。

傳送函式

傳送函式與先前的函式也稍微相似。

@IBAction func redSend(_ sender: Any) {
    if redAmount.text == "" {
        present(invalidAlert, animated: true, completion: nil)
    } else {
        transaction(from: "\(firstAccount)", to: "\(secondAccount)", amount: Int(redAmount.text!)!, type: "normal")
        print("\(redAmount.text!) BTC sent from \(firstAccount) to \(secondAccount)")
        chainState()
        redAmount.text = ""
    }
}
    
@IBAction func blueSend(_ sender: Any) {
    if blueAmount.text == "" {
        present(invalidAlert, animated: true, completion: nil)
    } else {
        transaction(from: "\(secondAccount)", to: "\(firstAccount)", amount: Int(blueAmount.text!)!, type: "normal")
        print("\(blueAmount.text!) BTC sent from \(secondAccount) to \(firstAccount)")
        chainState()
        blueAmount.text = ""
    }
}

首先,我們確認 redAmountblueAmount 中的文字欄位是否為空值。如果是,我們會顯示一個交易無效的警告。如果不是,我們就可以繼續。我們使用 transaction 函式輸入金額,並把交易設為 normal 型態,以將第一個帳號的金額傳送到第二個帳號(或相反)。我們印出被傳送的金額,然後呼叫 chainState() 函式。最後,把文字欄位清空。

這樣我們就完成囉!確認一下你的程式碼是否符合下圖所示。

執行 App 試試看!從前端來說,它看起來就如一個普通的交易 App,但你會知道它後台的運作。試試使用 App 將 BTC 從一個帳號交易給另一個帳號、並試著欺騙 App 吧!

結論

在這次的教學中,你學到了如何使用 Swift 來建立一個區塊鏈,並建立自己的比特幣交易。請注意在真實的加密貨幣後台裡,實作部分是跟上文是完全不一樣的東西,因為它需要藉由智慧合約來分散,但是上面的示範內容用來學習的。

在這個範例中,我們運用了比特幣來當加密貨幣,但你能想到區塊鏈還的其他用途嗎?歡迎在下面留言分享你的看法!希望你在此學到新的東西!

你可以在 Github 下載完整專案作參考。

譯者簡介:楊敦凱-目前於科技公司擔任 iOS Developer,工作之餘開發自有 iOS App同時關注網路上有趣的新玩意、話題及科技資訊。平時的興趣則是與自身專業無關的歷史、地理、棒球。來信請寄到:[email protected]

原文Building Your First Blockchain App in Swift

作者
Sai Kambampati
Sai Kambampati 是程式開發員,生活於美國加州薩克拉門托,於2017獲得Apple's WWDC獎學金。精於 Swift及Python語言,渴望自家開發人工智能產品。閒時喜歡觀看Netflix、做健身或是遛漣圖書館中。請到推特追蹤 @Sai_K1065 。
評論
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。