如何编写用于闪电网络守护进程的Java gRPC客户端

该文章介绍了如何使用Java编写gRPC客户端与Lightning Network Daemon (LND) 交互。文章提供了详细的设置、安装步骤,包括项目结构、pom.xml配置,以及Main.java的示例代码。通过这些步骤,开发者可以建立与LND节点的连接,并进行基本的信息查询操作。

如何为闪电网络守护进程编写 Java 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/<username>/Library/Application Support/Lnd/tls.cert";
  private static final String MACAROON_PATH = "/Users/<username>/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon";
  private static final String HOST = "localhost";
  private static final int PORT = 10009;

  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 代码,则此选项无效。

  • 原文链接: github.com/lightningnetw...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
lightningnetwork
lightningnetwork
江湖只有他的大名,没有他的介绍。