天天看點

超級賬本發現之旅(三):深度分析第一個區塊鍊應用

上一篇 文章中, 通過執行node query.js, 查詢Fabric 網絡, 并傳回了10輛車的資訊:

#node query.js      

指令行的輸出如下:

這是10輛車。 由Adriana擁有的黑色特斯拉模型S,由Brad擁有的紅色福特野馬,由名叫Pari的人擁有的紫羅蘭菲亞特Punto等等。 分類帳是基于鍵/值的,在這個實作中,關鍵值是從CAR0到CAR9。 這一點将變得特别重要。

查詢賬本的實作

現在讓我們來看看底層的實作。 使用編輯器(例如atom或visual studio)并打開query.js程式。

應用程式的初始部分定義了某些變量,如鍊碼,通道名稱和網絡端點:

下面的代碼用來構造對于汽車的查詢, 注意前面的注釋, 這個注釋中指明, 如果調用queryCar, 則參數args就要傳入汽車的key, 也就是CAR0等;在這個例子中指明是用queryAllCars, 則傳回所有的car對象

在上面的request對象中, 通過chaincodeId來指定需要調用的chaincode,如上面所示, chaincode是fabcar.

那麼這個名為fabcar的chaincode, 具體是什麼樣子的呢?來看一下代碼。首先這個chaincode是放在下面的這個目錄下的:

打開這個chaincode 源檔案,是用Go 語言編寫的, 最上面定義了SmartContract 以及Car 兩個類, 其中Car 是主要的Model 對象, 有Make,Model等幾個屬性。

下面的兩個方法則是和Fabric 網絡有關, 主要是通過shim對象進行互動。

    第一個方法是Init,從注釋中看, init 方法會在chaincode 被執行個體化時被執行。注釋還提及一個最佳實踐, 就是建議不要存放任何業務邏輯, 而是把初始化資料等業務邏輯放在一個單獨的方法中進行調用,這裡是initLedger方法。

    第二個方法是Invoke, 也就是應用程式對于區塊鍊網絡的通路, 這裡使用Invoke進行通路。在方法内部, 首先通過GetFunctionAndParameters方法來擷取要調用的函數方法和參數。這裡可以看出, Go 語言和Javascript 語言一樣, 變量可以不定義直接使用, Go 語言編譯器會根據上下文推導變量的類型;而且還可以傳回多個變量。

    這裡面需要注意的第一點就是, 對于不了解Go語言的同學來說,函數名Init 前面的部分 (s *SmartContract) 是難以了解的, 實際上可以把這個看做Go語言的類方法,記得最前面的SmartContract嗎? 前面的SmartContract 代碼塊中, SmartContract是空的:

// Define the Smart Contract structure

type SmartContract struct {

}

   這個實際上就是Go語言的特色之一, 類方法的動态添加;在這裡給SmartContract添加了Init和Invoke 兩個方法, 當Invoke 方法被調用時, 則根據傳入的參數, 執行queryCar還有queryAllCars等方法。

    下面幾個業務方法有  initLedger,queryCar,queryAllCars,createCar和changeCarOwner。 我們來仔細看一下queryAllCars函數,看看它如何與Fabric進行互動。

該函數使用Shim接口的函數GetStateByRange在startKey和endKey的args之間傳回賬本資料。 這些鍵分别定義為CAR0和CAR999。 是以,我們理論上可以建立1,000輛汽車(假設鑰匙被正确标記),并且一個queryAllCars會顯示每一個。這個方法的下半部分是轉換成json格式傳回。

    下面是應用程式調用不同chaincode方法和區塊鍊網絡進行交易的示意圖:

之前我們看到了queryAllCars方法的調用示例, 下面來嘗試一下其他的方法。

查詢特定車輛

    傳回到query.js程式并編輯構造函數請求來查詢特定的車。 我們将通過将函數從queryAllCars更改為queryCar并将特定的“Key”更改為args參數。 我們在這裡使用CAR4。 是以我們編輯的query.js程式現在應該包含以下内容:

然後來執行一下:

#node query.js

結果如下:

可以看到最下面的輸出:

是以我們從查詢所有車到隻查詢一個,Adriana的黑色特斯拉模型S.使用queryCar函數,我們可以查詢任何關鍵字(例如CAR0),并獲得與該車相對應的任何代碼,模型,顔色和所有者。

    現在,您應該對鍊碼中的基本查詢功能以及查詢程式中的少數參數感到舒适。 更新分類帳的時間到了。。。

更新賬本

    現在我們已經完成了幾個賬本查詢并添加了一些代碼,我們已經準備好更新分類帳。 讓我們為新手開一輛新車。

    賬本更新的工作,從應用産生一個交易提案(transaction proposal)開始。就像查詢一樣, 需要構造一個請求對象(request)來确定channel ID, 方法和特定的隻能合約, 來指定一個事務(transaction)。 這個應用下一步會調用

channel.SendTransactionProposal    

這個API 來發送交易提案到對等節點來執行背書(endorsement)。

    區塊鍊網絡(如背書節點, endorsing peer) 傳回一個提案響應(proposal response), 應用會利用這個對象來建構和簽名交易請求(transaction request), 這個交易請求會通過調用channel.sendTransction API, 發送到ordering service 節點。  Ordering Service 會把這個事務打包到一個區塊中, 并把這個區塊發送到channel 中的所有節點來執行驗證(在這個例子中隻有一個背書節點)。

   最後, 應用會調用eh.setPeerAddr API來連接配接peer 節點的事件監聽端口, 然後通過調用eh.registerTxEvent 來注冊和特定事務ID 相關聯的事件。 這個API 允許應用來獲知一個特定事務的最終狀态(例如成功送出或者失敗)。把這個過程想象成一個通知機制會更有利于了解。

    這裡并不打算更多的解釋事務的生命周期, 後續會有更多介紹。

    在這次的最初的invoke 調用中, 我們僅僅是建立一個新的asset:汽車。 在fabcar 目錄中,有一個單獨的Javascript 檔案 ——invoke.js  我們會使用這個檔案來執行事務。

    打開文本編輯器, 檢視如下代碼:

    你會看到我們可以調用兩個函數之一 -  createCar或changeCarOwner。 讓我們創造一個紅色的雪佛蘭伏特,并把它交給一個名叫尼克的業主。 我們在分類帳上使用CAR9,是以我們将使用CAR10作為識别鍵。 更新的代碼塊應如下所示:

儲存并執行代碼:

#node invoke.js

結果會有很多的輸出:

然後,我們把注意力在這一行:

Peer 節點發出事件通知, 我們的應用由于通過eh.registerTxEvent API , 會接收到通知。

    現在, 我們傳回query.js, 把代碼修改為查詢key為'CAR11'的汽車資訊:

然後執行

檢視結果, 發現我們的奔馳C200已經顯示出來了:

車輛過戶

還有一個changeCarOwner的智能合約沒有用到, 現在, 你可以自己實作這個功能了嗎?

原文釋出時間為:2017年08月26日

本文作者:查理曼大帝

本文來源:

CSDN

,如需轉載請聯系原作者。

繼續閱讀