如何用Java编写与lnd通信的gRPC客户端?

本节列举了用 Java 编写与 lnd 通信的客户端所需执行的操作。我们将使用 Maven 作为我们的构建工具。

前提条件

  • Maven
  • 运行中的 lnd
  • 运行中的 btcd

设置和安装

项目结构

.

├── pom.xml

└── src

  ├── main

     ├── java

     │ └── Main.java

     ├── proto

        └── lnrpc

           └── lightning.proto
注意 proto 文件夹,所有 proto 文件都保存在这里。

pom.xml

<properties> <grpc.version>1.36.0</grpc.version> </properties>
以下依赖是必需的。
<dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-tcnative-boringssl-static</artifactId> <version>2.0.28.Final</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.11</version> </dependency> </dependencies>
在构建部分,我们需要配置以下内容:
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.2.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

Main.java

使用以下代码设置通道和客户端以连接到你的 lnd 节点。

请注意,当使用 IP 地址连接到节点时(例如,使用 192.168.1.21 而不是 localhost),你需要将 --tlsextraip=192.168.1.21 添加到你的 lnd 配置中,并重新生成证书(删除 tls.cert 和 tls.key 并重启 lnd)。
```
import io.grpc.Attributes;
import io.grpc.CallCredentials;
import io.grpc.ManagedChannel;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContext;
import lnrpc.LightningGrpc;
import lnrpc.LightningGrpc.LightningBlockingStub;
import lnrpc.Rpc.GetInfoRequest;
import lnrpc.Rpc.GetInfoResponse;
import org.apache.commons.codec.binary.Hex;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.Executor;

public class Main {
 static class MacaroonCallCredential extends CallCredentials {
   private final String macaroon;

MacaroonCallCredential(String macaroon) {
  this.macaroon = macaroon;
}

@Override
public void applyRequestMetadata(RequestInfo requestInfo, Executor executor, MetadataApplier metadataApplier) {
  executor.execute(() -> {
    try {
      Metadata headers = new Metadata();
      Metadata.Key<String> macaroonKey = Metadata.Key.of("macaroon", Metadata.ASCII_STRING_MARSHALLER);
      headers.put(macaroonKey, macaroon);
      metadataApplier.apply(headers);
    } catch (Throwable e) {
      metadataApplier.fail(Status.UNAUTHENTICATED.withCause(e));
    }
  });
}

@Override
public void thisUsesUnstableApi() {
}

}

private static final String CERT_PATH = "/Users/

public static void main(String...args) throws IOException {
   SslContext sslContext = GrpcSslContexts.forClient().trustManager(new File(CERT_PATH)).build();
   NettyChannelBuilder channelBuilder = NettyChannelBuilder.forAddress(HOST, PORT);
   ManagedChannel channel = channelBuilder.sslContext(sslContext).build();

String macaroon =
    Hex.encodeHexString(
        Files.readAllBytes(Paths.get(MACAROON_PATH))
    );

LightningBlockingStub stub = LightningGrpc
    .newBlockingStub(channel)
    .withCallCredentials(new MacaroonCallCredential(macaroon));

GetInfoResponse response = stub.getInfo(GetInfoRequest.getDefaultInstance());
System.out.println(response.getIdentityPubkey());

}
}
```

运行示例

pom.xml 文件所在的目录中执行以下命令。
$ mvn compile exec:java -Dexec.mainClass="Main" -Dexec.cleanupDaemonThreads=false

示例输出

[INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Detecting the operating system and CPU architecture [INFO] ------------------------------------------------------------------------ [INFO] os.detected.name: osx [INFO] os.detected.arch: x86_64 [INFO] os.detected.version: 10.15 [INFO] os.detected.version.major: 10 [INFO] os.detected.version.minor: 15 [INFO] os.detected.classifier: osx-x86_64 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building lightning-client 0.0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- protobuf-maven-plugin:0.6.1:compile (default) @ lightning-client --- [INFO] Compiling 3 proto file(s) to /Users/<username>/Documents/Projects/lightningclient/target/generated-sources/protobuf/java [INFO] [INFO] --- protobuf-maven-plugin:0.6.1:compile-custom (default) @ lightning-client --- [INFO] Compiling 3 proto file(s) to /Users/<username>/Documents/Projects/lightningclient/target/generated-sources/protobuf/grpc-java [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ lightning-client --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 0 resource [INFO] Copying 3 resources [INFO] Copying 3 resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ lightning-client --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 12 source files to /Users/<username>/Documents/Projects/lightningclient/target/classes [INFO] [INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ lightning-client --- 032562215c38dede6f1f2f262ff4c8db58a38ecf889e8e907eee8e4c320e0b5e81 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.408 s [INFO] Finished at: 2018-01-13T19:05:49+01:00 [INFO] Final Memory: 30M/589M [INFO] ------------------------------------------------------------------------

Java proto 选项

lightning.proto 文件中有 2 个可用选项:
- option java_multiple_files = true;
- option java_package = "network.lightning.rpc";

你想要为生成的 Java 类使用的包。 如果在 .proto 文件中没有给出明确的 java_package 选项,那么默认情况下将使用 proto 包(使用 .proto 文件中的 “package” 关键字指定)。 但是,proto 包通常不能很好地用作 Java 包,因为 proto 包不应以反向域名开头。 如果不生成 Java 代码,则此选项无效。

标签:

上一篇:币安Alpha上线Aleo代币并启动空投及交易大赛
下一篇:Pyth Network:区块链预言机的金融数据革命