您已經定義並啓動了本地區塊鏈網絡,並且已構建 Java shim 客戶端 JAR 並安裝到本地 Maven 存儲庫中,如今已準備好在以前下載的 Hyperledger Fabric 附帶的一個 Java 鏈代碼示例上構建、註冊和調用交易。html
部署並運行鏈代碼java
您將執行如下步驟:git
導航到 $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example 目錄。github
接下來,經過命令行,使用此命令啓動 Gradle 構建軟件:web
gradle -b build.gradle build
您會看到如下輸出:json
$ cd GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example $ gradle -b build.gradle build Starting a Gradle Daemon (subsequent builds will be faster) :examples:chaincode:java:Example:compileJava :examples:chaincode:java:Example:processResources UP-TO-DATE :examples:chaincode:java:Example:classes :examples:chaincode:java:Example:jar :examples:chaincode:java:Example:startScripts :examples:chaincode:java:Example:distTar :examples:chaincode:java:Example:distZip :examples:chaincode:java:Example:assemble :examples:chaincode:java:Example:compileTestJava UP-TO-DATE :examples:chaincode:java:Example:processTestResources UP-TO-DATE :examples:chaincode:java:Example:testClasses UP-TO-DATE :examples:chaincode:java:Example:test UP-TO-DATE :examples:chaincode:java:Example:check UP-TO-DATE :examples:chaincode:java:Example:build :examples:chaincode:java:Example:copyToLib BUILD SUCCESSFUL Total time: 6.935 secs
該構建過程經過兩種形式建立了一個位於目錄 build/distributions 中的獨立發行版:TAR 文件和 ZIP 文件,每一個文件都包含運行鏈代碼所需的全部資源,其中包括一個用於驅動鏈代碼的名爲 Example 的腳本。網絡
Example 鏈代碼如今已準備好向本地區塊鏈網絡註冊。編輯器
確保本地區塊鏈網絡正在運行。若是未運行,則須要啓動它。若是須要溫習一下相關內容,請參閱「啓動區塊鏈網絡」部分。ide
若是您未在 $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example 目錄下,請導航到這裏。函數
接下來,將 Example.zip(或 Example.tar)解壓到 build/distributions 目錄中:
$ cd $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example $ cd build/distributions/ $ unzip Example.zip Archive: Example.zip inflating: Example/lib/chaincode.jar inflating: Example/lib/grpc-all-0.13.2.jar inflating: Example/lib/commons-cli-1.3.1.jar inflating: Example/lib/shim-client-1.0.jar inflating: Example/lib/grpc-netty-0.13.2.jar inflating: Example/lib/grpc-auth-0.13.2.jar inflating: Example/lib/grpc-protobuf-nano-0.13.2.jar inflating: Example/lib/grpc-core-0.13.2.jar inflating: Example/lib/grpc-protobuf-0.13.2.jar inflating: Example/lib/grpc-okhttp-0.13.2.jar inflating: Example/lib/grpc-stub-0.13.2.jar inflating: Example/lib/protobuf-java-3.0.0.jar inflating: Example/lib/netty-tcnative-boringssl-static-1.1.33.Fork21-osx-x86_64.jar inflating: Example/lib/netty-codec-http2-4.1.0.CR3.jar inflating: Example/lib/google-auth-library-oauth2-http-0.3.0.jar inflating: Example/lib/guava-18.0.jar inflating: Example/lib/protobuf-javanano-3.0.0-alpha-5.jar inflating: Example/lib/jsr305-3.0.0.jar inflating: Example/lib/okio-1.6.0.jar inflating: Example/lib/okhttp-2.5.0.jar inflating: Example/lib/netty-codec-http-4.1.0.CR3.jar inflating: Example/lib/netty-handler-4.1.0.CR3.jar inflating: Example/lib/google-auth-library-credentials-0.3.0.jar inflating: Example/lib/google-http-client-1.19.0.jar inflating: Example/lib/google-http-client-jackson2-1.19.0.jar inflating: Example/lib/netty-codec-4.1.0.CR3.jar inflating: Example/lib/netty-buffer-4.1.0.CR3.jar inflating: Example/lib/netty-transport-4.1.0.CR3.jar inflating: Example/lib/httpclient-4.0.1.jar inflating: Example/lib/jackson-core-2.1.3.jar inflating: Example/lib/netty-common-4.1.0.CR3.jar inflating: Example/lib/netty-resolver-4.1.0.CR3.jar inflating: Example/lib/httpcore-4.0.1.jar inflating: Example/lib/commons-logging-1.1.1.jar inflating: Example/lib/commons-codec-1.3.jar inflating: Example/bin/Example inflating: Example/bin/Example.bat
您可能想知道 「爲什麼有如此多的文件?」該發行版包含(在獨立進程中)單獨運行鏈代碼所需的一切資源,以及全部依賴 JAR 文件。
要註冊鏈代碼示例,可在 build/distributions 文件夾中執行如下腳本:
./Example/bin/Example
這會運行一個獨立進程來向本地區塊鏈網絡註冊鏈代碼示例。您會看到如下終端窗口輸出:
$ ./Example/bin/Example Hello world! starting [Ljava.lang.String;@7ef20235 Feb 22, 2017 10:05:08 AM example.Example main INFO: starting Feb 22, 2017 10:05:08 AM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection INFO: Inside newPeerCLientConnection Feb 22, 2017 10:05:08 AM io.grpc.internal.TransportSet$1 call INFO: Created transport io.grpc.netty.NettyClientTransport@3dd7b80b(/127.0.0.1:7051) for /127.0.0.1:7051 Feb 22, 2017 10:05:14 AM io.grpc.internal.TransportSet$TransportListener transportReady INFO: Transport io.grpc.netty.NettyClientTransport@3dd7b80b(/127.0.0.1:7051) for /127.0.0.1:7051 is ready
查看本地區塊鏈網絡的控制檯,您會看到如下輸出行:
. . vp0_1 | 16:05:14.048 [chaincode] HandleChaincodeStream -> DEBU 06d Current context deadline = 0001-01-01 00:00:00 +0000 UTC, ok = false vp0_1 | 16:05:14.065 [chaincode] processStream -> DEBU 06e []Received message REGISTER from shim vp0_1 | 16:05:14.065 [chaincode] HandleMessage -> DEBU 06f []Handling ChaincodeMessage of type: REGISTER in state created vp0_1 | 16:05:14.065 [chaincode] beforeRegisterEvent -> DEBU 070 Received REGISTER in state created vp0_1 | 16:05:14.065 [chaincode] registerHandler -> DEBU 071 registered handler complete for chaincode hello vp0_1 | 16:05:14.065 [chaincode] beforeRegisterEvent -> DEBU 072 Got REGISTER for chaincodeID = name:"hello" , sending back REGISTERED . .
記下注冊日誌輸出中的 chaincodeID name(示例中爲 hello;如上面 第 8 行 所示)。之後在經過結構的 REST 接口部署 Example 鏈代碼時,JSON 消息中須要使用此信息。
上面的輸出代表 Example 鏈代碼正在運行,並且已向本地區塊鏈驗證對等網絡註冊,並作好了部署準備。
Hyperledger Fabric 提供了一個用於與該結構交互的 REST Web 服務接口。與 fabric 的第一次交互是部署鏈代碼。確保本地區塊鏈網絡正在運行,而後啓動 SoapUI,單擊 REST 按鈕建立一個新的 REST 項目。您會看到一個相似圖 3 的對話框,在其中輸入用於全部 REST 請求的基礎 URL:
輸入 http://localhost:7050 做爲 URL,而後單擊 OK。端口 7050 是 fabric 使用的默認 REST 端口,並且由於區塊鏈網絡是在本地計算機上運行的,因此將使用 localhost 做爲主機名。
在 SoapUI 啓動後,能夠執行一次快速冒煙測試,以確保它能與本地區塊鏈網絡進行通訊。展開剛建立的新的 REST 資源,直到看到 Request 1,而後在 Editor 窗口中打開它。使用 GET 方法,在 resource 下輸入 /chain。確保單擊了 output 選項卡上的 JSON 選項,而後運行請求(經過單擊 arrow 圖標)。執行此請求時,會在 Editor 窗口右側的輸出選項卡中返回當前區塊的哈希值,如圖 4 所示:
若是看到一條相似圖 4 的 JSON 消息(固然您的網絡的 currentBlockHash 值會有所不一樣),那麼您已準備好部署 Example 鏈代碼。
右鍵單擊 REST Project 1 (http://localhost:7050) 下的端點並選擇 New Resource;您會看到一個包含 Resource Path 字段的 「New REST Resource」 對話框(參見圖 5):
輸入 /chaincode 做爲 resource path,而後單擊 OK,您會看到 SoapUI Projects 面板中顯示了新資源。打開對此資源的請求(默認狀況下該請求名爲 Request 1),將方法更改成 POST,並將此 JSON 粘貼到請求編輯器窗口左下角的請求區域:
{ "jsonrpc": "2.0", "method": "deploy", "params": { "type": 1, "chaincodeID":{ "name": "hello" }, "CtorMsg": { "args": [""] } }, "id": 1 }
有 3 點須要注意:
第 3 行:method 值必須爲 deploy。
第 6-7 行:JSON 消息中的 chaincodeID.name 必須與您在上一節中註冊 Example 鏈代碼時所用的 chaincodeID 匹配(在 Example 鏈代碼中,該值爲 hello)。
第 13 行:id 值用於協調請求。本教程不須要過多地考慮它,但要注意的是,在響應中始終會發送回該值(參見下一個清單)。
提交此請求時,JSON 輸出應以下所示:
{ "jsonrpc": "2.0", "result": { "status": "OK", "message": "hello" }, "id": 1 }
圖 6 給出了 SoapUI 中的輸出的屏幕截圖。JSON 輸出消息會顯示在輸出選項卡中,該選項卡位於請求編輯器的右側。
終端窗口中的網絡日誌輸出應包含如下行:
. . vp0_1 | 20:48:39.482 [rest] ProcessChaincode -> INFO 0c4 REST processing chaincode request... vp0_1 | 20:48:39.482 [rest] processChaincodeDeploy -> INFO 0c5 REST deploying chaincode... vp0_1 | 20:48:39.483 [devops] Deploy -> DEBU 0c6 Creating deployment transaction (hello) vp0_1 | 20:48:39.483 [devops] Deploy -> DEBU 0c7 Sending deploy transaction (hello) to validator vp0_1 | 20:48:39.483 [peer] sendTransactionsToLocalEngine -> DEBU 0c8 Marshalling transaction CHAINCODE_DEPLOY to send to local engine vp0_1 | 20:48:39.483 [peer] sendTransactionsToLocalEngine -> DEBU 0c9 Sending message CHAIN_TRANSACTION with timestamp seconds:1487796519 nanos:483661510 to local engine vp0_1 | 20:48:39.483 [consensus/noops] RecvMsg -> DEBU 0ca Handling Message of type: CHAIN_TRANSACTION vp0_1 | 20:48:39.483 [consensus/noops] broadcastConsensusMsg -> DEBU 0cb Broadcasting CONSENSUS vp0_1 | 20:48:39.483 [peer] Broadcast -> DEBU 0cc Broadcast took 1.135s vp0_1 | 20:48:39.483 [consensus/noops] RecvMsg -> DEBU 0cd Sending to channel tx uuid: hello vp0_1 | 20:48:39.483 [rest] processChaincodeDeploy -> INFO 0ce Successfully deployed chainCode: hello vp0_1 | 20:48:39.484 [rest] ProcessChaincode -> INFO 0cf REST successfully deploy chaincode: {"jsonrpc":"2.0","result":{"status":"OK","message":"hello"},"id":1} . .
第 3-4 行顯示了輸出,代表網絡已收到部署消息,而且該結構正在部署鏈代碼。第 13-14 行代表鏈代碼已成功部署。
在運行鏈代碼的終端窗口中,能夠注意到如下輸出:
$ ./build/distributions/Example/bin/Example Hello world! starting [Ljava.lang.String;@7ef20235 Feb 22, 2017 2:44:43 PM example.Example main INFO: starting Feb 22, 2017 2:44:43 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection INFO: Inside newPeerCLientConnection Feb 22, 2017 2:44:43 PM io.grpc.internal.TransportSet$1 call INFO: Created transport io.grpc.netty.NettyClientTransport@46adccd3(/127.0.0.1:7051) for /127.0.0.1:7051 Feb 22, 2017 2:44:48 PM io.grpc.internal.TransportSet$TransportListener transportReady INFO: Transport io.grpc.netty.NettyClientTransport@46adccd3(/127.0.0.1:7051) for /127.0.0.1:7051 is ready Feb 22, 2017 2:48:40 PM example.Example run INFO: In run, function: Feb 22, 2017 2:48:40 PM example.Example run
我包含了全部上下文輸出,在向區塊鏈網絡發送部署消息時,您會看到相似第 11-13 行的消息。
最後,將會調用 hello 方法,能夠看到它會在運行鏈代碼的終端窗口的日誌消息中顯示出來。
在 SoapUI 中的 chaincode 資源下,右鍵單擊 Method 1 並選擇 Clone Method。將該方法命名爲 Invoke,而後單擊 OK。打開新的 Invoke 方法下的 Request 1,並粘貼到如下 JSON 請求中:
{ "jsonrpc": "2.0", "method": "invoke", "params": { "type": 1, "chaincodeID":{ "name": "hello" }, "CtorMsg": { "args": ["hello"] } }, "id": 2 }
運行該請求時,會看到如下 JSON 響應:
{ "jsonrpc":"2.0", "result": { "status":"OK", "message":"1c1811d0-a958-4c58-ab1d-e1df550c18a3" }, "id":2 }
圖 7 給出了 SoapUI 中的輸出的屏幕截圖
網絡日誌輸出應包含如下行:
. . vp0_1 | 21:44:35.143 [rest] ProcessChaincode -> INFO 555 REST processing chaincode request... vp0_1 | 21:44:35.143 [rest] processChaincodeInvokeOrQuery -> INFO 556 REST invoke chaincode... vp0_1 | 21:44:35.143 [devops] invokeOrQuery -> INFO 557 Transaction ID: 1c1811d0-a958-4c58-ab1d-e1df550c18a3 vp0_1 | 21:44:35.143 [devops] createExecTx -> DEBU 558 Creating invocation transaction (1c1811d0-a958-4c58-ab1d-e1df550c18a3) vp0_1 | 21:44:35.143 [devops] invokeOrQuery -> DEBU 559 Sending invocation transaction (1c1811d0-a958-4c58-ab1d-e1df550c18a3) to validator vp0_1 | 21:44:35.143 [peer] sendTransactionsToLocalEngine -> DEBU 55a Marshalling transaction CHAINCODE_INVOKE to send to local engine vp0_1 | 21:44:35.143 [peer] sendTransactionsToLocalEngine -> DEBU 55b Sending message CHAIN_TRANSACTION with timestamp seconds:1487799875 nanos:143438691 to local engine vp0_1 | 21:44:35.143 [consensus/noops] RecvMsg -> DEBU 55c Handling Message of type: CHAIN_TRANSACTION vp0_1 | 21:44:35.143 [consensus/noops] broadcastConsensusMsg -> DEBU 55d Broadcasting CONSENSUS vp0_1 | 21:44:35.143 [peer] Broadcast -> DEBU 55e Broadcast took 1.249s vp0_1 | 21:44:35.143 [consensus/noops] RecvMsg -> DEBU 55f Sending to channel tx uuid: 1c1811d0-a958-4c58-ab1d-e1df550c18a3 vp0_1 | 21:44:35.143 [rest] processChaincodeInvokeOrQuery -> INFO 560 Successfully submitted invoke transaction with txid (1c1811d0-a958-4c58-ab1d-e1df550c18a3) vp0_1 | 21:44:35.143 [rest] ProcessChaincode -> INFO 561 REST successfully submitted invoke transaction: {"jsonrpc":"2.0","result":{"status":"OK","message":"1c1811d0-a958-4c58-ab1d-e1df550c18a3"},"id":2} . .
鏈代碼日誌輸出以下所示:
$ ./build/distributions/Example/bin/Example Hello world! starting [Ljava.lang.String;@7ef20235 Feb 22, 2017 3:26:57 PM example.Example main INFO: starting Feb 22, 2017 3:26:57 PM org.hyperledger.java.shim.ChaincodeBase newPeerClientConnection INFO: Inside newPeerCLientConnection Feb 22, 2017 3:26:57 PM io.grpc.internal.TransportSet$1 call INFO: Created transport io.grpc.netty.NettyClientTransport@765e4953(/127.0.0.1:7051) for /127.0.0.1:7051 Feb 22, 2017 3:27:02 PM io.grpc.internal.TransportSet$TransportListener transportReady INFO: Transport io.grpc.netty.NettyClientTransport@765e4953(/127.0.0.1:7051) for /127.0.0.1:7051 is ready Feb 22, 2017 3:27:24 PM example.Example run INFO: In run, function: Feb 22, 2017 3:27:24 PM example.Example run SEVERE: No matching case for function: Feb 22, 2017 3:30:55 PM example.Example run INFO: In run, function:hello hello invoked
我再次給出了全部鏈代碼輸出。您能夠看到哪些地方(第 16 行)調用了 hello 函數。
如今您已知道如何在本地區塊鏈網絡上構建、部署和運行 Java 鏈代碼。在下一節中,將會使用 Eclipse IDE(幾乎)從頭編寫一個鏈代碼程序,使用 Gradle 構建該鏈代碼程序,而後使用 SoapUI 體驗它。
若是你但願高效的學習以太坊DApp開發,能夠訪問匯智網提供的最熱門在線互動教程:
- 適合區塊鏈新手的以太坊智能合約和DApp實戰入門教程
- 區塊鏈+IPFS+Node.js+MongoDB+Express去中心化以太坊電商應用開發實戰
- web3j教程,一個講解java使用web3j開發以太坊區塊鏈的教程
其餘更多內容也能夠訪問這個以太坊博客。