部署并运行 Java 链代码示例

您已经定义并启动了本地区块链网络,而且已构建 Java shim 客户端 JAR 并安装到本地 Maven 存储库中,现在已准备好在之前下载的 Hyperledger Fabric 附带的一个 Java 链代码示例上构建、注册和调用交易。

部署并运行链代码

您将执行以下步骤:

  • 使用 Gradle 构建示例。
  • 通过运行 Gradle 构建软件为您创建的脚本,向验证对等网络注册该示例。
  • 使用 SoapUI 将示例部署到本地区块链网络。
  • 使用 SoapUI 在示例链代码上调用交易。

1.构建示例

导航到 $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/java/Example 目录。

接下来,通过命令行,使用此命令启动 Gradle 构建软件:

gradle -b build.gradle build

您会看到以下输出:

$ 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 链代码现在已准备好向本地区块链网络注册。

2.注册示例

确保本地区块链网络正在运行。如果未运行,则需要启动它。如果需要温习一下相关内容,请参阅“启动区块链网络”部分。

如果您未在 $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 链代码正在运行,而且已向本地区块链验证对等网络注册,并做好了部署准备。

3.部署示例

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 行的消息。

4.在示例上调用交易

最后,将会调用 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 体验它。

顺便分享两个教程:

1.区块链新手以太坊DApp入门实战

2.区块链进阶以太坊电商平台实战

用Java为Hyperledger Fabric(超级账本)开发区块链智能合约链代码之部署与运行示例代码的更多相关文章

  1. 用Java为Hyperledger Fabric(超级账本)编写区块链智能合约链代码

    编写第一个 Java 链代码程序 在上一节中,您已经熟悉了如何构建.运行.部署和调用链代码,但尚未编写任何 Java 代码. 在本节中,将会使用 Eclipse IDE.一个用于 Eclipse 的 ...

  2. hyperledger fabric超级账本java sdk样例e2e代码流程分析

     一  checkConfig  Before     1.1  private static final TestConfig testConfig = TestConfig.getConfig() ...

  3. 用Hyperledger Fabric(超级账本)来构建Java语言开发区块链的环境

    面向 Java 开发人员的链代码简介 您或许听说过区块链,但可能不确定它对 Java™ 开发人员有何用.本教程将帮助大家解惑.我将分步展示如何使用 Hyperledger Fabric v0.6 来构 ...

  4. Hyperledger Fabric Chaincode for Operators——实操智能合约

    什么是Chaincode(智能合约)? chaincode是一个程序,它是使用Go语言编写的,最终在Java等其他编程语言中实现了指定的接口.chaincode运行在一个被背书peer进程独立出来的安 ...

  5. 基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例

    相关实验源码已上传:https://github.com/wefantasy/FabricLearn 前言 在基于truffle框架实现以太坊公开拍卖智能合约中我们已经实现了以太坊智能合约的编写及部署 ...

  6. 第一行代码:以太坊(2)-使用Solidity语言开发和测试智能合约

    智能合约是以太坊的核心之一,用户可以利用智能合约实现更灵活的代币以及其他DApp.不过在深入讲解如何开发智能合约之前,需要先介绍一下以太坊中用于开发智能合约的Solidity语言,以及相关的开发和测试 ...

  7. 区块链之Hyperledger(超级账本)Fabric v1.0 的环境搭建(更新)

    参考链接:https://blog.csdn.net/so5418418/article/details/78355868   https://blog.csdn.net/wgh1015398431/ ...

  8. Hyperledger Fabric Ledger——账本总账

    Ledger Ledger(账本)即所有的state transitions(状态切换),是有序且不可篡改的.state transitions(状态切换)是由参与方提交的chaincode(智能合约 ...

  9. Hyperledger Fabric 手动搭建【区块链学习三】

    Hyperledger Fabric 手动搭建 前面我们学习了区块链是什么.还有自动搭建学习东西我们就要从简单到深入(入门到放弃),现在自动部署已经跑通了接下来就是手动搭建Fabric 网络可以更好的 ...

随机推荐

  1. Mina源码阅读笔记(一)-整体解读

    今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...

  2. day07_Tomcat服务器与http学习笔记

    ============================================================ 一.Tomcat服务器(很熟悉) 1.Web开发概述 WEB,在英语中web即 ...

  3. 计算机网络-TCP/IP HTTP Conclusion

    1.1OSI 与 TCP/IP 各层的结构 1.2 三次握手和四次挥手,TCP为什么三次握手,四次挥手 在第一次消息发送中,A随机选取一个序列号作为自己的初始序号发送给B:第二次消息B使用ack对A的 ...

  4. 我如何踏上IT路

    第一次开技术博客,第一篇博文就聊聊自己是如何走上IT这条路的.一直听人说"搞IT的"颇含贬低色彩,也有IT前辈奉劝不要轻易踏上这条路,但最终我这个本是化学化工专业的门外汉还是义无反 ...

  5. for循环嵌套讲解:

    1.for循环嵌套讲解: class ForForDemo {     public static void main(String[] args)     {         //大圈套小圈思想: ...

  6. 一个基础的for循环面试题

    下面的这段程序主要考察的就是for循环的基础,输出什么?????? [html] view plaincopyprint? public class test { /** * @param args ...

  7. JSP指令与动作

    Jsp基本指令和动作 (2011-08-18 16:25:13) 转载▼ 标签: 杂谈 分类: java JSP基本指令 jsp命令指令用来设置与整个jsp页面相关的属性,它并不直接产生任何可见的输出 ...

  8. JMS(Java平台上的专业技术规范)

    JMS(Java平台上的专业技术规范) 编辑   jms即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应 ...

  9. OSGi简介

    OSGi简介 OSGi是什么 下面来看看“维基百科”给出的解释: OSGi(Open Service Gateway Initiative)有双重含义.一方面它指OSGi Alliance组织:另一方 ...

  10. linux上安装redis的踩坑过程

    redis用处很广泛,我不再啰嗦了,我按照网上教程想在linux上安装下,开始了踩坑过程,网上买了一个linux centos7.3,滴滴云的,巨坑无比啊,不建议大家用这家的! redis 为4.0, ...