您好,登錄后才能下訂單哦!
小編給大家分享一下Hyperledger Fabric如何編寫第一個Java鏈代碼程序,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
在本節中,將會使用 Eclipse IDE、一個用于 Eclipse 的 Gradle 插件,以及一個名為 ChaincodeTutorial 的 Java 鏈代碼框架項目,編寫第一個 Java 鏈代碼程序。您將從我為此教程創建的 GitHub 存儲庫中獲取框架代碼,將該代碼導入 Eclipse 中,添加代碼來讓鏈代碼智慧合同按要求生效,然后在 Eclipse IDE 內使用 Gradle 構建該代碼。
您將執行的步驟如下:
安裝適用于 Eclipse 的 Gradle Buildship 插件。
從 GitHub 克隆 ChaincodeTutorial 項目。
將該項目導入 Eclipse 中。
探索該鏈代碼框架項目。
編寫 Java 鏈代碼。
構建 Java 鏈代碼。 完成本節后,您的鏈代碼就可以在本地區塊鏈網絡上運行了。
您使用自己喜歡的任何 IDE,但本教程中的說明是針對 Eclipse 的。備注:Buildship Gradle 插件有助于將 Gradle 與 Eclipse 集成,但仍然需要將 Gradle 安裝在計算機上。
如果您一直在按照教程進行操作,那么您應該已經將 Gradle 安裝在計算機上;如果尚未安裝它,請立即安裝。請參閱 “安裝構建軟件” 部分,了解如何將 Gradle 安裝在計算機上。
在 Buildship Gradle Integration 下,單擊 Install 按鈕并按照提示進行操作。單擊 Finish 后,將安裝適用于 Eclipse 的 Buildship Gradle 插件,而且會要求您重啟 Eclipse。
重新打開 Eclipse 后,Gradle 應該已經與 Eclipse IDE 全面集成。您現在已準備好從 GItHub 克隆 ChaincodeTutorial 存儲庫。
配置 Eclipse IDE 和 Gradle集成后,將從 GitHub 克隆 ChaincodeTutorial 代碼并將其導入 Eclipse 中。打開一個命令提示符或終端窗口,導航到 $GOPATH 并執行以下命令:
git clone https://github.com/makotogo/ChaincodeTutorial.git
命令輸出應類似于:
$ export GOPATH=/Users/sperry/home/mychaincode $ cd $GOPATH $ git clone https://github.com/makotogo/ChaincodeTutorial.git Cloning into 'ChaincodeTutorial'... remote: Counting objects: 133, done. remote: Compressing objects: 100% (90/90), done. remote: Total 133 (delta 16), reused 118 (delta 1), pack-reused 0 Receiving objects: 100% (133/133), 9.39 MiB | 1.95 MiB/s, done. Resolving deltas: 100% (16/16), done. $ cd ChaincodeTutorial $ pwd /Users/sperry/home/mychaincode/ChaincodeTutorial
此命令將 Blockchain ChaincodeTutorial 存儲庫從 GitHub 克隆到 $GOPATH。它包含一個 Java 鏈代碼框架項目,您可以在本地區塊鏈網絡中構建、運行和測試它。
但在執行所有這些操作之前,需要將該代碼導入 Eclipse 中。
在 Eclipse 中,轉到 File > Import...> Gradle > Existing Gradle Project。這會打開一個向導對話框(參見圖 9)。
單擊 Next。在向導中隨后出現的對話框中(參見圖 10),瀏覽到 $GOPATH/ChaincodeTutorial,然后單擊 Finish 導入該項目。
完成項目導入后,確保選擇了 Java Perspective,您剛導入的 ChaincodeTutorial 項目會顯示在 Project Explorer 視圖中。
將代碼導入 Eclipse 工作區后,就可以編寫鏈代碼了。
在本節中,將探索該鏈代碼項目,以便理解在編寫任何 Java 代碼前它應該如何運行。
作為開發人員,我們喜歡編寫代碼,所以我不想讓您失去編寫 Java 代碼的機會。但是,項目設置可能很復雜,我不想讓這些設置阻礙實現本教程的主要目的。為此,我提供了您所需的大部分代碼。
首先讓我們快速查看一下基類 AbstractChaincode,它位于 com.makotojava.learn.blockchain.chaincode 包中,如清單 1 所示。
清單 1. AbstractChaincode 類
package com.makotojava.learn.blockchain.chaincode; import java.util.Arrays; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperledger.java.shim.ChaincodeBase; import org.hyperledger.java.shim.ChaincodeStub; public abstract class AbstractChaincode extends ChaincodeBase { private static final Log log = LogFactory.getLog(AbstractChaincode.class); public static final String FUNCTION_INIT = "init"; public static final String FUNCTION_QUERY = "query"; protected abstract String handleInit(ChaincodeStub stub, String[] args); protected abstract String handleQuery(ChaincodeStub stub, String[] args); protected abstract String handleOther(ChaincodeStub stub, String function, String[] args); @Override public String run(ChaincodeStub stub, String function, String[] args) { String ret; log.info("Greetings from run(): function -> " + function + " | args -> " + Arrays.toString(args)); switch (function) { case FUNCTION_INIT: ret = handleInit(stub, args); break; case FUNCTION_QUERY: ret = handleQuery(stub, args); default: ret = handleOther(stub, function, args); break; } return ret; } @Override public String query(ChaincodeStub stub, String function, String[] args) { return handleQuery(stub, args); } }
我想指出的第一點是,AbstractChaincode 是 ChaincodeBase 的子類,后者來自該結構的 shim 客戶端(第 7、10 行)。
第 17-19 行顯示了需要在 ChaincodeLog 類(AbstractChaincode 的子類)中實現的方法,這些方法分別用于實現初始化、賬本查詢和日志功能。
第 22-36 行顯示了 ChaincodeBase 類(來自鏈代碼 shim 客戶端)的 run() 方法,我們可以在其中查看調用了哪個函數,以及該調用應委托給哪個處理函數。該類是可擴展的,因為 init 和 query 以外的其他任何函數(比如 log 函數)都由 handleOther() 處理,所以您還必須實現它。
現在打開 com.makotojava.learn.blockchain.chaincode 包中的 ChaincodeLog 類。
我只提供了一個框架供您填充 — 也就是說,我僅提供了編譯它所需的代碼。您需要編寫剩余代碼。您應該執行 JUnit 測試,然后會看到測試失敗(因為還未編寫實現)和失敗的原因。換句話說,可以使用 JUnit 測試作為指導來正確地實現代碼。
現在,如果感覺難以理解,不要擔心;我在 com.makotojava.learn.blockchain.chaincode.solution 中提供了解決方案,以防您遇到阻礙(或者想根據參考來幫助完成實現)。
首先介紹一下在 ChaincodeLog 中實現鏈代碼方法需要了解的一些背景。Java 鏈代碼通過 ChaincodeStub 類與 Hyperledger Fabric 框架進行通信,另外需要記住,賬本是區塊鏈技術的透明性方面的核心。讓智能合約(責任性)發揮其作用的是賬本的狀態,而鏈代碼是通過 ChaincodeStub 來評估賬本的狀態。通過訪問賬本狀態,可以實現一個智能合約(也即鏈代碼)。
ChaincodeStub 上有許多方法可用于在賬本的當前狀態中存儲、檢索和刪除數據項,但本教程僅討論兩個方法,它們用于存儲和檢索賬本狀態:
putState(String key, String value)— 將指定的狀態值存儲在賬本中,該值被相應映射到指定的鍵。
getState()— 獲取與指定鍵關聯的狀態值,并以字符串形式返回它。
為本教程編寫代碼時,只需在賬本中存儲或檢索狀態值,就會使用 putState() 或 getState() 函數。ChaincodeLog 類僅在賬本中存儲和檢索值來實現其智能合約,所以實現這些方法只需知道該值即可。更復雜的鏈代碼將使用 ChaincodeStub 中的其他一些方法(但這些方法不屬于本教程的介紹范疇)。
我非常喜歡測試驅動開發 (TDD),所以按照 TDD 的方式,我首先編寫單元測試。繼續運行它們,并觀察它們的失敗過程。在這之后,編寫符合規范的代碼,直到單元測試得到通過。單元測試的工作是確保能夠獲得預期的行為,通過研究單元測試,您將獲得實現這些方法所需的足夠信息。
但是,我還在每個方法頂部編寫了 javadoc 注釋,這可能有所幫助(以防您不熟悉 TDD 或 JUnit)。在學完本節的內容后,在 JUnit 測試中的代碼與框架 ChaincodeLog 中的 javadoc 注釋之間,你應該知道有實現鏈代碼所需的所有信息。
從 Project Explorer 視圖(在 Java 透視圖中),導航到 ChaincodeLogTest 類,右鍵單擊它并選擇 Run As > Gradle Test。在它運行時,您會看到如圖 11 所示的結果,其中顯示了運行的所有 Gradle 任務的樹結構。成功完成的任務在旁邊會用一個復選標記進行指示。
Gradle Executions 選項卡中的感嘆號表示與失敗的單元測試對應的 Gradle 任務(跟我們期望的一樣,所有 4 個單元測試都失敗了)。
由于我們編寫 JUnit 測試案例的方式,每個測試方法對應于 ChaincodeLog 中的一個方法,您需要在本教程中正確實現它們。
實現 getChaincodeID() 首先,需要實現 getChaincodeID()。它的合約要求返回鏈代碼的唯一標識符。我在 ChaincodeLog 類的頂部定義了一個名為 CHAINCODE_ID 的常量,您會用到它。可以自由更改它的值,但是,如果要更改 getChaincodeID() 返回的鏈代碼 ID,請確保它在您的網絡中是唯一的,而且不要忘記更改 JSON 消息的 ChaincodeID.name 屬性。
/** * Returns the unique chaincode ID for this chaincode program. */ @Override public String getChaincodeID() { return null;// ADD YOUR CODE HERE }
練習:完成 getChaincodeID() 方法。如果需要一個參考,請參見 com.makotojava.learn.blockchain.chaincode.solution 包。
實現 handleInit()
接下來將實現 handleInit() 方法。它的合約要求處理鏈代碼程序的初始化,在本例中,這意味著它將向賬本添加一條(由調用方指定的)消息,并在調用成功時將該消息返回給調用方。
/** * Handles initializing this chaincode program. * * Caller expects this method to: * * 1. Use args[0] as the key for logging. * 2. Use args[1] as the log message. * 3. Return the logged message. */ @Override protected String handleInit(ChaincodeStub stub, String[] args) { return null;// ADD YOUR CODE HERE }
練習:完成 handieInit() 方法。如果需要一個參考,請參見 com.makotojava.learn.blockchain.chaincode.solution 包。
實現 handleQuery()
接下來將實現 handleQuery() 方法。它的合約要求查詢賬本,為此,它會獲取指定的鍵,在賬本中查詢與這個(這些)鍵匹配的值,然后將該(這些)值返回給調用方。如果指定了多個鍵,應該使用逗號分隔返回的值。
/** * Handles querying the ledger. * * Caller expects this method to: * * 1. Use args[0] as the key for ledger query. * 2. Return the ledger value matching the specified key * (which should be the message that was logged using that key). */ @Override protected String handleQuery(ChaincodeStub stub, String[] args) { return null;// ADD YOUR CODE HERE }
確保編寫了代碼來輸出查詢調用的結果,以便可以在控制臺輸出中查看結果(如果想了解我是如何做的,請參閱解決方案)。
練習:完成 handleQuery() 方法。如果需要一個參考,請參見 com.makotojava.learn.blockchain.chaincode.solution 包。
實現 handleOther()
最后需要實現 handleOther() 方法,它的合約要求處理其他消息(這是完全開放的,但正因如此它才是可擴展的)。您將在這里實現 log 函數,它的合同要求將調用方指定的一條消息添加到賬本中,并在調用成功時將該消息返回給調用方。這看起來與 init 函數中發生的事非常相似,所以或許您可以在該實現中利用此函數。
/** * Handles other methods applied to the ledger. * Currently, that functionality is limited to these functions: * - log * * Caller expects this method to: * Use args[0] as the key for logging. * Use args[1] as the log message. * Return the logged message. */ @Override protected String handleOther(ChaincodeStub stub, String function, String[] args) { // TODO Auto-generated method stub return null;// ADD YOUR CODE HERE }
練習:完成 handleOther() 方法。如果需要一個參考,請參見 com.makotojava.learn.blockchain.chaincode.solution 包。
如果您為前面的每個練習編寫的代碼滿足本節(以及代碼注釋中)為它們設定的要求,JUnit 測試應該都能通過,而且將鏈代碼部署在本地區塊鏈網絡中并運行時,它們應該能夠正常工作。
請記住,如果遇到阻礙,我提供了一個解決方案(但是在查看解決方案之前,您必須自行實現這些方法)。
現在您已編寫 Java 鏈代碼且通過了所有 JUnit 測試,是時候使用 Eclipse 和用于 Eclipse 的 Gradle Buildship 插件構建鏈代碼了。通過轉到 Window > Show View > Other... 調出 Gradle Tasks 視圖,然后搜索 gradle,選擇 Gradle Tasks,并單擊 OK。(參見圖 12。)
Gradle Tasks 視圖打開后,展開 ChaincodeTutorial > build 節點,選擇 build 和 clean。(參見圖 13。)
右鍵單擊 build 和 clean,然后選擇 Run Gradle Tasks(Gradle 將確定運行它們的正確順序)。您的 Gradle Executions 視圖應該顯示一個干凈的構建版本,如圖 14 所示,其中每項的旁邊僅有一個復選標記。
完成構建后,$GOPATH/ChaincodeTutorial 目錄(您之前已從 GitHub 將代碼克隆到這里)下有一個子目錄 build/distributions,它包含您的鏈代碼(這應該看起來很熟悉,因為本教程前面的 hello 示例中已經這么做過)。
構建 Java 鏈代碼后,就可以在本地區塊鏈網絡中部署和運行它,并在它之上調用交易。
在本節中,將會啟動并注冊您的鏈代碼,部署它,并通過 Hyperledger Fabric REST 接口在鏈代碼之上調用交易,就像本教程前面對 hello 示例所做的一樣。確保本地區塊鏈正在運行(如想溫習一下相關內容,請參閱 “啟動區塊鏈網絡” 部分)。
您將執行以下步驟:
注冊 Java 鏈代碼。
部署 Java 鏈代碼。
在 Java 鏈代碼上調用交易。
您需要提取 build/distributions/ChaincodeTutorial.zip 文件并運行鏈代碼腳本,就像本教程前面運行 hello 示例時一樣(參見 “注冊示例” 部分)。
運行 ChaincodeTutorial 腳本時,輸出應如下所示:
$ ./ChaincodeTutorial/bin/ChaincodeTutorial Feb 28, 2017 4:18:16 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection INFO: Inside newPeerCLientConnection Feb 28, 2017 4:18:16 PM io.grpc.internal.TransportSet$1 call INFO: Created transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 Feb 28, 2017 4:18:21 PM io.grpc.internal.TransportSet$TransportListener transportReady INFO: Transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
現在您的 Java 鏈代碼已向本地區塊鏈網絡注冊,您已準備好部署和測試鏈代碼了。
就像對 hello 示例鏈代碼執行的操作一樣,將會使用該結構的 REST 接口部署 Java 鏈代碼,并在它之上調用交易。
打開 SoapUI。如果愿意的話,可以自行創建一個新 REST 項目和它的所有請求,或者可以導入我包含在之前克隆的 GitHub 項目中的 SoapUI REST 項目。該 SoapUI 項目位于 $GOPATH/ChaincodeTutorial 目錄中。
要部署鏈代碼,可以導航到 ChaincodeLog Deploy 請求(如圖 15 所示)并提交該請求。
如果沒有使用來自 GitHub 的 SoapUI 項目(或者使用不同的 HTTP 客戶端),那么應該提交的 JSON 請求如下所示:
{ "jsonrpc": "2.0", "method": "deploy", "params": { "type": 4, "chaincodeID":{ "name": "ChaincodeLogSmartContract" }, "ctorMsg": { "args": ["init", "KEY-1", "Chaincode Initialized"] } }, "id": 1 }
提交請求。如果請求被成功處理,您會獲得以下 JSON 響應:
{ "jsonrpc": "2.0", "result": { "status": "OK", "message": "ChaincodeLogSmartContract" }, "id": 1 }
現在您的鏈代碼已部署并準備好運行。
部署并初始化 Java 鏈代碼后,就可以在它之上調用交易了。在本節中,將會調用 log 和 query 函數作為交易。
要調用 log 函數,可以打開 ChaincodeLog Log 請求并提交它。(參見圖 16。)
如果沒有使用來自 GitHub 的 SoapUI 項目(或者使用不同的 HTTP 客戶端),那么應該提交的 JSON 請求如下所示:
{ "jsonrpc": "2.0", "method": "invoke", "params": { "type": 1, "chaincodeID":{ "name": "ChaincodeLogSmartContract" }, "CtorMsg": { "args": ["log", "KEY-2", "This is a log message."] } }, "id": 2 }
如果請求被成功處理,您會獲得以下 JSON 響應:
{ "jsonrpc": "2.0", "result": { "status": "OK", "message": "a6f7a4fc-2980-4d95-9ec2-114dd9d0e4a5" }, "id": 2 }
要調用 query 函數,可以打開 ChaincodeLog Query 請求并提交它。(參見圖 17。)
如果沒有使用來自 GitHub 的 SoapUI 項目(或者使用不同的 HTTP 客戶端),那么應該提交的 JSON 請求如下所示:
{ "jsonrpc": "2.0", "method": "invoke", "params": { "type": 1, "chaincodeID":{ "name": "ChaincodeLogSmartContract" }, "ctorMsg": { "args": ["query", "KEY-1", "KEY-2"] } }, "id": 3 }
如果請求被成功處理,您會獲得以下 JSON 響應:
{ "jsonrpc": "2.0", "result": { "status": "OK", "message": "84cbe0e2-a83e-4edf-9ce9-71ae7289d390" }, "id": 3 }
解決方案代碼的終端窗口輸出類似于:
$ ./ChaincodeTutorial/bin/ChaincodeTutorial Feb 28, 2017 4:18:16 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection INFO: Inside newPeerCLientConnection Feb 28, 2017 4:18:16 PM io.grpc.internal.TransportSet$1 call INFO: Created transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 Feb 28, 2017 4:18:21 PM io.grpc.internal.TransportSet$TransportListener transportReady INFO: Transport io.grpc.netty.NettyClientTransport@10bf86d3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready Feb 28, 2017 4:34:52 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run INFO: Greetings from run(): function -> init | args -> [KEY-1, Chaincode Initialized] Feb 28, 2017 4:34:52 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleLog INFO: *** Storing log message (K,V) -> (ChaincodeLogSmartContract-CLSC-KEY-1,Chaincode Initialized) *** Feb 28, 2017 4:50:27 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run INFO: Greetings from run(): function -> log | args -> [KEY-2, This is a log message.] Feb 28, 2017 4:50:27 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleLog INFO: *** Storing log message (K,V) -> (ChaincodeLogSmartContract-CLSC-KEY-2,This is a log message.) *** Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.AbstractChaincode run INFO: Greetings from run(): function -> query | args -> [KEY-1, KEY-2] Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleQuery INFO: *** Query: For key 'ChaincodeLogSmartContract-CLSC-KEY-1, value is 'Chaincode Initialized' *** Feb 28, 2017 5:02:13 PM com.makotojava.learn.blockchain.chaincode.solution.ChaincodeLog handleQuery INFO: *** Query: For key 'ChaincodeLogSmartContract-CLSC-KEY-2, value is 'This is a log message.' ***
以上是“Hyperledger Fabric如何編寫第一個Java鏈代碼程序”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。