java - 尝试将 hyperledger Fabric SDK 与 Spring REST Controller 集成时出现以下错误

标签 java spring maven hyperledger-fabric grpc

我正在做的事情背后的想法是使用 Spring REST API 公开 super 账本结构区 block 链。 当我构建代码(没有 REST)并使用 java 命令调用它时,它工作正常并从 Hyperledger 结构返回数据。 然而,当我尝试在 REST Controller 中实现它时,我发现自己被阻止了。

下面是我的 Rest Controller 代码:

@RestController
public class RestWebController {

private static final Logger log = Logger.getLogger(RestWebController.class);

@RequestMapping(value = "/getall", method = RequestMethod.GET)
public void getAll(){
    try {
       HFCAClient caClient = getHfCaClient("http://localhost:7054", null);

    // enroll or load admin
    AppUser admin = getAdmin(caClient);
    log.info(admin);

    // register and enroll new user
    AppUser appUser = getUser(caClient, admin, "hfuser");
    log.info(appUser);

    // get HFC client instance
    HFClient client = getHfClient();
    // set user context
    client.setUserContext(admin);

    // get HFC channel using the client
    Channel channel = getChannel(client);
    log.info("Channel: " + channel.getName());

    // call query blockchain example
    queryBlockChain(client);
}
catch (Exception e) {
        e.printStackTrace();

    }
}



    /**
 * Invoke blockchain query
 *
 * @param client The HF Client
 * @throws ProposalException
 * @throws InvalidArgumentException
 */
static void queryBlockChain(HFClient client) throws ProposalException, InvalidArgumentException {
    // get channel instance from client
    Channel channel = client.getChannel("mychannel");
    // create chaincode request
    QueryByChaincodeRequest qpr = client.newQueryProposalRequest();
    // build cc id providing the chaincode name. Version is omitted here.
    ChaincodeID fabcarCCId = ChaincodeID.newBuilder().setName("poc-app").build();
    qpr.setChaincodeID(fabcarCCId);
    // CC function to be called
    qpr.setFcn("queryAllTransactions");
    Collection<ProposalResponse> res = channel.queryByChaincode(qpr);
    // display response
    for (ProposalResponse pres : res) {
        String stringResponse = new String(pres.getChaincodeActionResponsePayload());
        log.info(stringResponse);
    }
}

/**
 * Initialize and get HF channel
 *
 * @param client The HFC client
 * @return Initialized channel
 * @throws InvalidArgumentException
 * @throws TransactionException
 */
static Channel getChannel(HFClient client) throws InvalidArgumentException, TransactionException {
    // initialize channel
    // peer name and endpoint in fabcar network
    Peer peer = client.newPeer("peer0.org1.example.com", "grpc://localhost:7051");
    // eventhub name and endpoint in fabcar network
    EventHub eventHub = client.newEventHub("eventhub01", "grpc://localhost:7053");
    // orderer name and endpoint in fabcar network
    Orderer orderer = client.newOrderer("orderer.example.com", "grpc://localhost:7050");
    // channel name in fabcar network
    Channel channel = client.newChannel("mychannel");
    channel.addPeer(peer);
    channel.addEventHub(eventHub);
    channel.addOrderer(orderer);
    channel.initialize();
    return channel;
}

/**
 * Create new HLF client
 *
 * @return new HLF client instance. Never null.
 * @throws CryptoException
 * @throws InvalidArgumentException
 */
static HFClient getHfClient() throws Exception {
    // initialize default cryptosuite
    CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
    // setup the client
    HFClient client = HFClient.createNewInstance();
    client.setCryptoSuite(cryptoSuite);
    return client;
}


/**
 * Register and enroll user with userId.
 * If AppUser object with the name already exist on fs it will be loaded and
 * registration and enrollment will be skipped.
 *
 * @param caClient  The fabric-ca client.
 * @param registrar The registrar to be used.
 * @param userId    The user id.
 * @return AppUser instance with userId, affiliation,mspId and enrollment set.
 * @throws Exception
 */
static AppUser getUser(HFCAClient caClient, AppUser registrar, String userId) throws Exception {
    AppUser appUser = tryDeserialize(userId);
    if (appUser == null) {
        RegistrationRequest rr = new RegistrationRequest(userId, "org1");
        String enrollmentSecret = caClient.register(rr, registrar);
        Enrollment enrollment = caClient.enroll(userId, enrollmentSecret);
        appUser = new AppUser(userId, "org1", "Org1MSP", enrollment);
        serialize(appUser);
    }
    return appUser;
}

/**
 * Enroll admin into fabric-ca using {@code admin/adminpw} credentials.
 * If AppUser object already exist serialized on fs it will be loaded and
 * new enrollment will not be executed.
 *
 * @param caClient The fabric-ca client
 * @return AppUser instance with userid, affiliation, mspId and enrollment set
 * @throws Exception
 */
static AppUser getAdmin(HFCAClient caClient) throws Exception {
    AppUser admin = tryDeserialize("admin");
    if (admin == null) {
        Enrollment adminEnrollment = caClient.enroll("admin", "adminpw");
        admin = new AppUser("admin", "org1", "Org1MSP", adminEnrollment);
        serialize(admin);
    }
    return admin;
}

/**
 * Get new fabic-ca client
 *
 * @param caUrl              The fabric-ca-server endpoint url
 * @param caClientProperties The fabri-ca client properties. Can be null.
 * @return new client instance. never null.
 * @throws Exception
 */
static HFCAClient getHfCaClient(String caUrl, Properties caClientProperties) throws Exception {
    CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
    HFCAClient caClient = HFCAClient.createNewInstance(caUrl, caClientProperties);
    caClient.setCryptoSuite(cryptoSuite);
    return caClient;
}


// user serialization and deserialization utility functions
// files are stored in the base directory

/**
 * Serialize AppUser object to file
 *
 * @param appUser The object to be serialized
 * @throws IOException
 */
static void serialize(AppUser appUser) throws IOException {
    try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(
            Paths.get(appUser.getName() + ".jso")))) {
        oos.writeObject(appUser);
    }
}

/**
 * Deserialize AppUser object from file
 *
 * @param name The name of the user. Used to build file name ${name}.jso
 * @return
 * @throws Exception
 */
static AppUser tryDeserialize(String name) throws Exception {
    if (Files.exists(Paths.get(name + ".jso"))) {
        return deserialize(name);
    }
    return null;
}

static AppUser deserialize(String name) throws Exception {
    try (ObjectInputStream decoder = new ObjectInputStream(
            Files.newInputStream(Paths.get(name + ".jso")))) {
        return (AppUser) decoder.readObject();
    }
}

我使用mvn spring-boot:run运行spring boot,服务器正常启动。这是我的 pom.xml :

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>demo</name>
<description>Demo project for Spring Boot</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>


    <dependency>
        <groupId>org.hyperledger.fabric-sdk-java</groupId>
        <artifactId>fabric-sdk-java</artifactId>
        <version>1.0.0</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

在 localhost:8080/getall 上调用服务器后,我收到此错误:

2018-07-13 14:56:33.439  WARN 24669 --- [ault-executor-0] io.grpc.internal.ChannelExecutor         : Runnable threw exception in ChannelExecutor

java.lang.NoClassDefFoundError: io/netty/handler/codec/http2/internal/hpack/Decoder
    at io.grpc.netty.GrpcHttp2HeadersDecoder.<init>(GrpcHttp2HeadersDecoder.java:85) ~[grpc-netty-1.3.0.jar:1.3.0]
    at io.grpc.netty.GrpcHttp2HeadersDecoder$GrpcHttp2ClientHeadersDecoder.<init>(GrpcHttp2HeadersDecoder.java:147) ~[grpc-netty-1.3.0.jar:1.3.0]
    at io.grpc.netty.NettyClientHandler.newHandler(NettyClientHandler.java:119) ~[grpc-netty-1.3.0.jar:1.3.0]
    at io.grpc.netty.NettyClientTransport.start(NettyClientTransport.java:190) ~[grpc-netty-1.3.0.jar:1.3.0]
    at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:44) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:216) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:186) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.ManagedChannelImpl$SubchannelImplImpl.obtainActiveTransport(ManagedChannelImpl.java:812) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.GrpcUtil.getTransportFromPickResult(GrpcUtil.java:592) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.DelayedClientTransport.reprocess(DelayedClientTransport.java:295) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.ManagedChannelImpl$LbHelperImpl$5.run(ManagedChannelImpl.java:718) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:87) ~[grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:709) [grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:758) [grpc-core-1.3.0.jar:1.3.0]
    at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:175) [grpc-core-1.3.0.jar:1.3.0]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
Caused by: java.lang.ClassNotFoundException: io.netty.handler.codec.http2.internal.hpack.Decoder
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_171]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_171]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_171]
    ... 18 common frames omitted

2018-07-13 14:56:35.321 ERROR 24669 --- [nio-8080-exec-2] o.hyperledger.fabric.sdk.OrdererClient   : sendDeliver time exceeded for orderer

org.hyperledger.fabric.sdk.exception.TransactionException: sendDeliver time exceeded for orderer
    at org.hyperledger.fabric.sdk.OrdererClient.sendDeliver(OrdererClient.java:274) ~[fabric-sdk-java-1.0.0.jar:na]
    at org.hyperledger.fabric.sdk.Orderer.sendDeliver(Orderer.java:165) [fabric-sdk-java-1.0.0.jar:na]
    at org.hyperledger.fabric.sdk.Channel.getLatestBlock(Channel.java:1074) [fabric-sdk-java-1.0.0.jar:na]
    at org.hyperledger.fabric.sdk.Channel.getConfigurationBlock(Channel.java:898) [fabric-sdk-java-1.0.0.jar:na]
    at org.hyperledger.fabric.sdk.Channel.parseConfigBlock(Channel.java:826) [fabric-sdk-java-1.0.0.jar:na]
    at org.hyperledger.fabric.sdk.Channel.initialize(Channel.java:526) [fabric-sdk-java-1.0.0.jar:na]
    at com.example.demo.controller.RestWebController.getChannel(RestWebController.java:144) [classes/:na]
    at com.example.demo.controller.RestWebController.getAll(RestWebController.java:84) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.31.jar:8.5.31]

注意:通过独立调用 .jar,甚至运行 Hyperledger Fabric NodeJS sdk,网络工作正常。

最佳答案

NoClassDefFoundError 表示版本冲突。 gRPC 被编译为使用运行时不存在的方法。

使用mvn dependency:tree我看到正在使用Netty版本4.1.25.Final。但看看fabric-sdk-java 1.0.0 ,它使用 grpc-netty 1.3.0 和 Netty 4.1.8.Final。 spring-boot-starter-parent 正在拉入 spring-boot-dependencies选择 Netty 4.1.25.Final。

我建议升级到fabric-sdk-java 1.1.0,它使用grpc-netty 1.11.0和Netty 4.1.23.Final。然后通过设置 netty.version 属性覆盖 spring-boot-dependency 以使用 Netty 4.1.23.Final:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <netty.version>4.1.23.Final</netty.version> <!-- add this line -->
</properties>

关于java - 尝试将 hyperledger Fabric SDK 与 Spring REST Controller 集成时出现以下错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51324835/

相关文章:

java - 二十一点游戏,需要造型帮助

java - osgi框架中class.forName()和classLoader.loadClass()有什么区别

java - 从docker-compose使用时,flyway不会拾取迁移

java - Cassandra 更新不一致

java - 在 JUnit 中使用(out)存储库对 Spring Boot 服务类进行单元测试

Spring 预计至少有 1 个 bean 有资格作为此依赖项的 Autowiring 候选者

java - Neo4j 未正确保存标签

Maven - 如何编译测试而不运行它们?

java - 如何使用 onejar Maven 插件在 list 中设置额外的类路径条目?

android - 在项目中使用android swipelistview