基於區塊鏈技術的超級賬本 (Hyperledger) - 從理論到實戰

語言: CN / TW / HK

什麼是區塊鏈?簡單來說區塊鏈就是一個分散式的記賬本,或者分散式的資料庫。

區塊鏈的資料結構是一個連結串列,交易資料被儲存到連結串列的區塊中,區塊鏈的第一個區塊叫創世區塊,除了創世塊以外,每個區塊還包含前一個區塊的雜湊指標,這個雜湊指標的值是根據前一個區塊的實際資料計算出來的。雜湊指標指向前一個區塊,後面的區塊可以查詢前面所有區塊的資訊。

賬本的資料結構就是這樣的一個連結串列,那麼分散式的含義是什麼呢?

區塊鏈的眾多參與者組成了一個鬆散自治的 P2P 網路,我們把區塊鏈網路的參與者叫做節點,每個節點都擁有一個賬本拷貝,所有賬本的資訊都是一致的,在區塊鏈裡沒有中心節點。每當有新的交易進來,所有節點的賬本都會更新,並且最終保持一致。更新的方式不是去修改某個區塊的值,而是儲存交易記錄。比如在比特幣系統中,它沒有使用者資產記錄這樣的概念,不像普通資料庫那樣用一條資料儲存資產,比特幣使用者資產的值是通過把所有的交易記錄串聯聚合後得到的,賬戶裡資產的來源可以一直向上追溯,直到創世塊為止。區塊鏈裡的交易資料根據具體場景,可以是任何需要記錄的資訊。

智慧合約

為了支援資訊的持續更新,以及對賬本進行管理(寫入交易,進行查詢等),區塊鏈網路引入了智慧合約來實現對賬本的訪問和控制。智慧合約不僅僅可用於在區塊鏈網路中打包資訊,它們也可以被用於自動的執行由參與者定義的特定交易操作。

比如智慧合約可以規定物流中的運輸費用,根據物流的快慢收取不同的費用,根據貨物的到達時間進行自動轉賬等。上傳到區塊鏈網路中的的智慧合約會被打包到某一個區塊中,因此智慧合約一旦寫入區塊鏈,也是不可更改的。

共識機制

區塊鏈網路中交易資訊同步的過程,確保交易只有獲得適當參與者批准後才更新,所有的參與者都會將同樣的資訊按照同樣的順序更新,這樣的過程叫做共識。共識機制是區塊鏈的核心之一。

區塊鏈的第一個應用比特幣,採用的是 Proof of Work(工作量證明)的共識機制。簡單介紹一下比特幣的共識機制,演算法的具體細節大家可以去查白皮書。節點收到一個交易後,會根據判斷標準對該交易進行有效性校驗,無效的交易會被廢棄。通過有效性驗證之後的交易將會被廣播給其他節點。其他節點會做同樣的獨立校驗,當有效的交易達到整個網路所有節點時,即全網達成了“該交易有效”的共識。每個節點都會收到很多有效但是還未被打包到區塊中的交易,這些交易被組裝成 Merkle Tree,Merkle Tree 的第一個交易比較特殊,叫做 coinbase,由節點自己建立,將挖礦獎勵支付到礦工自己的地址。挖礦獎勵包括新建立的比特幣和打包進該區塊所有交易的手續費總額。然後節點計算一個符合難度的雜湊值,挖礦就是通過修改引數不斷計算區塊雜湊值,直至達到難度要求,也就間接證明了該節點付出了對應的工作量,這就是工作量證明。筆者的另一篇文章 300行ABAP程式碼實現一個最簡單的區塊鏈原型 裡用了一個 ABAP 方法 CL_ABAP_MESSAGE_DIGEST=>CALCULATE_HASH_FOR_CHAR 來計算區塊的雜湊值。

當節點計算出一個符合難度的區塊雜湊時,即說明該礦工挖礦成功了,該節點將該區塊組裝到本地的區塊鏈,同時也將此區塊廣播給其他節點。其他節點接收到該區塊後會驗證該區塊是否有效,有可能有兩個節點同時挖出了新的區塊 B1 和 B2,它們的上一個區塊都是同一個區塊 P。有的節點可能會先收到 B1,有的會先收到 B2,這時區塊鏈出現了暫時性的兩個分叉。要打破這種局面,要看下一個區塊是基於 B1 生成還是基於 B2 生成。如果基於 B1,B1 這條鏈就變成了最長鏈,其他包含 B2 的節點會重新選擇最長鏈,而 B2 作為孤塊被丟棄掉。

到目前為止,我們可以將區塊鏈看做是一個共享的,去中心化的多備份系統,通過智慧合約更新交易資料,同時藉助共識的協作流程使網路中所有的節點保持一致。

這裡的交易可以指代任何資料,例如:數字貨幣,合同,記錄或者其它任何資訊。

區塊鏈的型別

  • 公有鏈:網路中的節點可以任意接入,網路中資料讀寫許可權不受限制,所有節點都參與共識過程。比特幣,以太坊等數字貨幣都屬於公有鏈。

  • 私有鏈:網路中的節點被一個組織控制,由其獨享該區塊鏈的寫入許可權,私有鏈和其他的分散式儲存沒有太大區別。

  • 聯盟鏈:多個公司或組織通過授權接入,由某些節點參與共識過程。Hyperledger Fabric 屬於聯盟鏈。

什麼是 Hyperledger Fabric?

Hyperledger Fabric 是 Linux 基金會發起的 Hyperledger 專案之一。Hyperledger Fabric 專為在企業環境中使用而設計的開源的基於區塊鏈的分散式賬本。Hyperledger Fabric 可用於全球供應鏈管理、金融交易、資產記賬、人力資源、保險、健康和數字音樂等領域。

Hyperledger Fabric 中的賬本子系統(ledger)包括兩個元件:世界觀(world state)和事務日誌(transaction log)。世界觀記錄了賬本在特定時間點的現狀,是一個鍵值資料庫。交易日誌記錄產生世界狀態當前值的所有交易,是世界觀的更新歷史。賬本的世界觀的底層資料庫可以更換,可以選擇使用 levelDB 或 couchDB。

Hyperledger Fabric 是第一個支援以通用語言編寫智慧合約的區塊鏈平臺,可以使用 java,nodejs 和 go 語言來編寫智慧合約。Hyperledger Fabric 中的智慧合約也叫鏈碼(chain code)。

和其他公有區塊鏈平臺最大的不同,Hyperledger Fabric 是私有的並且需要授權才能接入,它擁有一個 MSP(Membership Service Provider) 模組專門提供成員管理服務。

CA(Certificate Authority) 負責許可權管理,成員身份相關證書管理 (Enrollment CertificateAuthority) 和維護交易相關證書管理 (Transaction Certificate Authority) 等等。

Hyperledger Fabric 提供了建立 channel 的功能,這允許參與者為交易新建一個單獨的賬本。當網路中的一些參與者是競爭對手時,這個功能變得尤為重要。因為這些參與者並不希望所有的交易資訊——比如提供給部分客戶的特定價格資訊——都對網路中所有參與者公開。只有在同一個 channel 中的參與者,才會擁有該 channel 中的賬本,而其他不在此 channel 中的參與者則看不到這個賬本。

Hyperledger Fabric 使用獨立的排序節點(order)來提供共識服務,負責排序交易,提供全域性確認的交易順序。

應用程式通過 SDK 訪問 Hyperledger Fabric。

最新版 Hyperledger Fabric 的設計中,根據功能將節點角色解耦開,讓不同節點處理不同型別的工作負載。從業務邏輯上又將節點分為背書節點(Endorser)和提交節點(Committer)。

  • Endorser peer:負責對來自客戶端的交易進行合法性和許可權檢查(模擬交易),通 過檢查則簽名並返回結果給客戶端。

  • Committer peer:負責維護賬本,將達成一致順序的批量交易結果進行狀態檢查,生成區塊,執行合法的交易,並寫入賬本,同一個物理節點可以同時擔任 endorser 和 committer 兩個角色。

Hyperledger Fabric 交易流程:共識

共識流程主要分 Proposal,Packaging 和 Validation 三個階段。

Proposal

應用提交一個交易 proposal,然後將其提交給所有的背書節點,後者接到後,將其作為輸入執行鏈碼生成相應的交易 proposal 響應。此時並不會更新 Ledger,而是對交易 proposal 響應簽名,並將其返回給應用。應用收到簽名後的響應,共識流程的第一階段就完成了。

Packaging

這個階段是 order 節點對交易進行排序打包。Order 節點從各個應用接收交易 proposal 響應,然後對這些交易進行排序,排序之後打包成區塊。

Validation

共識流程的最後一個階段,由 order 節點將區塊分發給所有和它連線的節點,這些節點將確認區塊中的交易都經過背書節點簽名,然後將確認後的區塊更新到 ledger 中。

整個流程稱為共識,所有節點都已對交易內容和順序達成一致,這一過程由 order 節點控制。 共識是一個多步驟的過程,只有在整個流程完成時才會更新賬本 ,可能每個節點的更新時間稍有不同。

構建一個 Hyperledger Fabric 平臺絕非易事,既需要硬體基礎設施的投入,也需要全方位的開發和運營管理(DevOps)。除了平臺本身,一套完整的解決方案,還包括裝置接入,訪問控制,服務監控等管理功能。

SAP Cloud Platform(下文簡稱 SCP )提供了開箱即用的 Hyperledger Fabric Service,為開發者提供了強大的服務支援:

  • 直觀友好的視覺化監控與操作介面,幫助開發者按需申請區塊鏈網路,建立管理節點、渠道,而無需考慮底層硬體資源。

  • 簡單易用的智慧合約開發與測試環境,方便開發者對應用程式碼進行管理。

  • 安全,隱私性方面的保障,並對相關資源進行了效能優化。

下面是具體的實戰步驟,該步驟使用 go 語言開發一組微服務,這組微服務包含讀和寫兩個 API,能夠將資料寫入架設於 SAP 雲平臺上的超級賬本服務。

簡單地說,應用程式通過智慧合約介面同超級賬本進行讀寫操作。我們將開發一個 Hello World 的智慧合約,部署到 SAP 雲平臺上。出於簡單起見,我們沒有開發應用,而是簡單地在 SAP 雲平臺的 API 控制檯上直接消費這個 Hello World 的智慧合約,對雲平臺上的超級賬本進行讀和寫。

開啟超級賬本專案 Fabric 的 github 倉庫地址:

https://github.com/hyperledger/fabric

發現 Fabric 專案是 Google 的程式語言 GoLang 開發的,因此咱們這個練習也使用 Go 語言來進行智慧合約的開發。

  1. 從 Google 網站上將 Go 語言 1.11 版的二進位制包下載到本地,解壓到 /usr/local 目錄下:

sudo tar -C /usr/local -xzf /home/vagrant/Downloads/go1.11.linux-amd64.tar.gz

將該目錄配置到環境變數 PATH 中去:

  1. Fabric 專案已經將智慧合約同超級賬本的通訊封裝到一個名叫 shim 的介面中,我們只需要在我們編寫的智慧合約程式碼中直接呼叫該 shim 介面即可。

我們使用 import 將這個 shim 介面的依賴引入進來,在第 14 行定義一個結構體,包含 ID 和 Value 兩個欄位。這個結構體即是待寫入超級賬本的資料結構,ABAP 顧問可以將其視為 ABAP 資料字典裡定義的結構體。

第 46 行定義的方法 Invoke 是這個最簡單的智慧合約的核心程式碼,cc *MessageStore 這個語法和 C 語言很像,定義了一個型別為 MessageStore 的指標變數 cc。這個指標變數同 C++ 的 this 指標和 ABAP 的 me 引用作用類似,在方法被呼叫時,指向了方法的呼叫者。

Invoke 後面括號裡的 stub shim.ChaincodeStubInterface 定義了該方法的輸入引數(形參)stub, 型別為 shim.ChaincodeStubInterface。

這個 Invoke 方法不會通過應用程式顯式呼叫,而是通過超級賬本程式回撥:當方法被呼叫時,指標 cc 和輸入引數 stub 已經自動被 Fabric 框架賦上了對應值。在 Invoke 方法執行的上下文裡,通過輸入引數 stub 判斷出當前回撥的場景是讀還是寫,然後進入對應的分支。分支內部呼叫我們自己開發的 write 和 read 方法同超級賬本進行互動。

這種通過同一個回撥函式內部的 switch case 來處理多個場景的做法,ABAP 和 Java 開發者應該都不陌生。比如下圖是通過 InvocationHandler 實現 Java 動態代理的例子,其中 invoke 方法的邏輯結構和本文智慧合約程式碼的結構非常相似。

關於 ABAP 和 Java 裡各種靜態代理和動態代理的寫法,請參考我的部落格:

Various Proxy Design Pattern implementation variants in Java, ABAP and JavaScript

  1. 將開發好的智慧合約原始檔構建成可執行檔案。這一步確保在部署智慧合約到 SAP 雲平臺之前,先在本地開發環境將所有潛在錯誤全部檢測出並修復。

  1. 登入 SAP 雲平臺,在 Service Marketplace 裡點選 Hyperledger Fabric 的超連結:

建立一個新的 Service 例項:

建立過程中需要填寫 channel 的 ID 和密匙。

區塊鏈分為公有鏈,私有鏈和聯盟鏈,而超級賬本屬於聯盟鏈。在聯盟鏈裡,有一個專門的稱為 MSP(Membership Service Provider)的模組,提供成員管理服務,只有授權使用者才能接入區塊鏈網路。這裡我事先在 SAP 雲平臺上建立了一個渠道並進行認證,因此此處直接輸入一個合法的渠道 ID 和密匙。關於 SAP 雲平臺上超級賬本渠道的建立和成員授權接入的步驟,請參考這篇 SAP 幫助文件

Service 例項建立完畢後,點選 Create Service Key 按鈕建立 key,目的是生成用於 OAuth 認證的 clientId 和 clientSecret,方便接下來的 API 呼叫。

點選 Service 例項的 Referencing Apps 面板,點選按鈕 Open Dashboard:

點選 Deploy Chaincode,選擇本地構建好的 zip 包,進行上傳並部署。這個按鈕同 SAP 雲平臺 CloudFoundry 環境部署本地應用的邏輯相同。

部署成功後,點選 Test Chaincode 超連結進入 API 控制檯。

該控制檯集成了 Swagger 框架,在呼叫 post 請求進行超級賬本的寫操作和 get 請求進行讀操作之前,先要點選 Authorize 按鈕進行身份認證:

輸入第四步建立 Service Key 後生成的 clientID 和 clientSecret 進行認證:

認證成功後,可以在 Swagger 的控制檯裡呼叫 post 和 get 請求了。

首先發送 post 請求,請求負載就是一個簡單的 json 物件,id 為 i042416,value 為 Hello World:

post 請求在 SAP 雲平臺上的超級賬本執行成功,返回 200 響應碼:

緊接著執行 get 請求,輸入剛才寫入的資料 id: i042416:

get 請求能夠將之前通過 post 請求寫入賬本的資料成功讀出來:

登入 SAP 雲平臺超級賬本控制檯,能看到之前通過 post 寫入的資料已經加入到區塊鏈尾部的區塊了。點選區塊可以檢視資料明細:

在超級賬本控制檯的 API Calls 和 Logs 面板裡也能看到每次超級賬本讀寫的詳細資訊。

總結

本文首先簡述了區塊鏈的基本設計原理和資料結構,然後介紹了 Hyperledger Fabric 這一業界首先支援以通用語言編寫智慧合約的區塊鏈平臺。最後以 Go 語言為例,展示瞭如何編寫一段簡單的智慧合約程式碼,並部署到 SAP 雲平臺上。該雲平臺的超級賬本服務,能幫助希望使用這項區塊鏈技術的企業避免了硬體基礎設施的投入,同時遮蔽了大部分超級賬本平臺管理的底層細節。

通過 SAP 雲平臺提供的控制檯,即可實現對超級賬本進行裝置接入,訪問控制,服務監控等管理功能。同時,通過 Go 語言編寫的智慧合約一旦部署到 SAP 雲平臺,生成的 Restful API 能夠被其他程式語言方便地消費。呼叫這些 API 寫入超級賬本區塊鏈中的資料將無法再被篡改。使用 SAP 雲平臺的超級賬本服務,應用開發人員可以無需將過多精力花費在超級賬本體系架構本身,從而能夠專注於應用邏輯的編寫上去。