github.com/decred/dcrlnd@v0.7.6/docs/grpc/java.md (about) 1 2 # How to write a Java gRPC client for the Lightning Network Daemon 3 4 This section enumerates what you need to do to write a client that communicates 5 with lnd in Java. We'll be using Maven as our build tool. 6 7 ### Prerequisites 8 - Maven 9 - running lnd 10 - running btcd 11 12 ### Setup and Installation 13 #### Project Structure 14 ``` 15 . 16 ├── pom.xml 17 └── src 18 ├── main 19 ├── java 20 │ └── Main.java 21 ├── proto 22 ├── google 23 │ └── api 24 │ ├── annotations.proto 25 │ └── http.proto 26 └── lnrpc 27 └── lightning.proto 28 29 ``` 30 Note the ***proto*** folder, where all the proto files are kept. 31 32 - [lightning.proto](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/lightning.proto) 33 - [annotations.proto](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/third_party/googleapis/google/api/annotations.proto) 34 - [http.proto](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/third_party/googleapis/google/api/http.proto) 35 36 #### pom.xml 37 ``` 38 <properties> 39 <grpc.version>1.8.0</grpc.version> 40 </properties> 41 ``` 42 The following dependencies are required. 43 ``` 44 <dependencies> 45 <dependency> 46 <groupId>io.grpc</groupId> 47 <artifactId>grpc-netty</artifactId> 48 <version>${grpc.version}</version> 49 </dependency> 50 <dependency> 51 <groupId>io.grpc</groupId> 52 <artifactId>grpc-protobuf</artifactId> 53 <version>${grpc.version}</version> 54 </dependency> 55 <dependency> 56 <groupId>io.grpc</groupId> 57 <artifactId>grpc-stub</artifactId> 58 <version>${grpc.version}</version> 59 </dependency> 60 <dependency> 61 <groupId>io.netty</groupId> 62 <artifactId>netty-tcnative-boringssl-static</artifactId> 63 <version>2.0.7.Final</version> 64 </dependency> 65 <dependency> 66 <groupId>commons-codec</groupId> 67 <artifactId>commons-codec</artifactId> 68 <version>1.11</version> 69 </dependency> 70 </dependencies> 71 ``` 72 In the build section, we'll need to configure the following things : 73 ``` 74 <build> 75 <extensions> 76 <extension> 77 <groupId>kr.motd.maven</groupId> 78 <artifactId>os-maven-plugin</artifactId> 79 <version>1.5.0.Final</version> 80 </extension> 81 </extensions> 82 <plugins> 83 <plugin> 84 <groupId>org.xolstice.maven.plugins</groupId> 85 <artifactId>protobuf-maven-plugin</artifactId> 86 <version>0.5.0</version> 87 <configuration> 88 <protocArtifact>com.google.protobuf:protoc:3.4.0:exe:${os.detected.classifier}</protocArtifact> 89 <pluginId>grpc-java</pluginId> 90 <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> 91 </configuration> 92 <executions> 93 <execution> 94 <goals> 95 <goal>compile</goal> 96 <goal>compile-custom</goal> 97 </goals> 98 </execution> 99 </executions> 100 </plugin> 101 </plugins> 102 </build> 103 ``` 104 #### Main.java 105 Use the code below to set up a channel and client to connect to your `lnd` node. 106 107 Note that when an IP address is used to connect to the node (e.g. 192.168.1.21 instead of localhost) you need to add `--tlsextraip=192.168.1.21` to your `lnd` configuration and re-generate the certificate (delete tls.cert and tls.key and restart lnd). 108 109 ```java 110 import io.grpc.Attributes; 111 import io.grpc.CallCredentials; 112 import io.grpc.ManagedChannel; 113 import io.grpc.Metadata; 114 import io.grpc.MethodDescriptor; 115 import io.grpc.Status; 116 import io.grpc.netty.GrpcSslContexts; 117 import io.grpc.netty.NettyChannelBuilder; 118 import io.netty.handler.ssl.SslContext; 119 import lnrpc.LightningGrpc; 120 import lnrpc.LightningGrpc.LightningBlockingStub; 121 import lnrpc.Rpc.GetInfoRequest; 122 import lnrpc.Rpc.GetInfoResponse; 123 import org.apache.commons.codec.binary.Hex; 124 125 import java.io.File; 126 import java.io.IOException; 127 import java.nio.file.Files; 128 import java.nio.file.Paths; 129 import java.util.concurrent.Executor; 130 131 public class Main { 132 static class MacaroonCallCredential implements CallCredentials { 133 private final String macaroon; 134 135 MacaroonCallCredential(String macaroon) { 136 this.macaroon = macaroon; 137 } 138 139 public void thisUsesUnstableApi() {} 140 141 public void applyRequestMetadata( 142 MethodDescriptor < ? , ? > methodDescriptor, 143 Attributes attributes, 144 Executor executor, 145 final MetadataApplier metadataApplier 146 ) { 147 String authority = attributes.get(ATTR_AUTHORITY); 148 System.out.println(authority); 149 executor.execute(new Runnable() { 150 public void run() { 151 try { 152 Metadata headers = new Metadata(); 153 Metadata.Key < String > macaroonKey = Metadata.Key.of("macaroon", Metadata.ASCII_STRING_MARSHALLER); 154 headers.put(macaroonKey, macaroon); 155 metadataApplier.apply(headers); 156 } catch (Throwable e) { 157 metadataApplier.fail(Status.UNAUTHENTICATED.withCause(e)); 158 } 159 } 160 }); 161 } 162 } 163 164 private static final String CERT_PATH = "/Users/user/Library/Application Support/Lnd/tls.cert"; 165 private static final String MACAROON_PATH = "/Users/user/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon"; 166 private static final String HOST = "localhost"; 167 private static final int PORT = 10009; 168 169 public static void main(String...args) throws IOException { 170 SslContext sslContext = GrpcSslContexts.forClient().trustManager(new File(CERT_PATH)).build(); 171 NettyChannelBuilder channelBuilder = NettyChannelBuilder.forAddress(HOST, PORT); 172 ManagedChannel channel = channelBuilder.sslContext(sslContext).build(); 173 174 String macaroon = 175 Hex.encodeHexString( 176 Files.readAllBytes(Paths.get(MACAROON_PATH)) 177 ); 178 179 LightningBlockingStub stub = LightningGrpc 180 .newBlockingStub(channel) 181 .withCallCredentials(new MacaroonCallCredential(macaroon)); 182 183 184 GetInfoResponse response = stub.getInfo(GetInfoRequest.getDefaultInstance()); 185 System.out.println(response.getIdentityPubkey()); 186 } 187 } 188 ``` 189 #### Running the example 190 Execute the following command in the directory where the **pom.xml** file is located. 191 ``` 192 mvn compile exec:java -Dexec.mainClass="Main" -Dexec.cleanupDaemonThreads=false 193 ``` 194 ##### Sample output 195 ``` 196 [INFO] Scanning for projects... 197 [INFO] ------------------------------------------------------------------------ 198 [INFO] Detecting the operating system and CPU architecture 199 [INFO] ------------------------------------------------------------------------ 200 [INFO] os.detected.name: osx 201 [INFO] os.detected.arch: x86_64 202 [INFO] os.detected.version: 10.13 203 [INFO] os.detected.version.major: 10 204 [INFO] os.detected.version.minor: 13 205 [INFO] os.detected.classifier: osx-x86_64 206 [INFO] 207 [INFO] ------------------------------------------------------------------------ 208 [INFO] Building lightning-client 0.0.1-SNAPSHOT 209 [INFO] ------------------------------------------------------------------------ 210 [INFO] 211 [INFO] --- protobuf-maven-plugin:0.5.0:compile (default) @ lightning-client --- 212 [INFO] Compiling 3 proto file(s) to /Users/user/Documents/Projects/lightningclient/target/generated-sources/protobuf/java 213 [INFO] 214 [INFO] --- protobuf-maven-plugin:0.5.0:compile-custom (default) @ lightning-client --- 215 [INFO] Compiling 3 proto file(s) to /Users/user/Documents/Projects/lightningclient/target/generated-sources/protobuf/grpc-java 216 [INFO] 217 [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ lightning-client --- 218 [INFO] Using 'UTF-8' encoding to copy filtered resources. 219 [INFO] Copying 0 resource 220 [INFO] Copying 3 resources 221 [INFO] Copying 3 resources 222 [INFO] 223 [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ lightning-client --- 224 [INFO] Changes detected - recompiling the module! 225 [INFO] Compiling 12 source files to /Users/user/Documents/Projects/lightningclient/target/classes 226 [INFO] 227 [INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ lightning-client --- 228 032562215c38dede6f1f2f262ff4c8db58a38ecf889e8e907eee8e4c320e0b5e81 229 [INFO] ------------------------------------------------------------------------ 230 [INFO] BUILD SUCCESS 231 [INFO] ------------------------------------------------------------------------ 232 [INFO] Total time: 7.408 s 233 [INFO] Finished at: 2018-01-13T19:05:49+01:00 234 [INFO] Final Memory: 30M/589M 235 [INFO] ------------------------------------------------------------------------ 236 ``` 237 238 ### Java proto options 239 240 There are 2 options available that can be used in the *lightning.proto* file : 241 242 * option java_multiple_files = true; 243 * option java_package = "network.lightning.rpc"; 244 >The package you want to use for your generated Java classes. If no explicit java_package option is given in the .proto file, then by default the proto package (specified using the "package" keyword in the .proto file) will be used. However, proto packages generally do not make good Java packages since proto packages are not expected to start with reverse domain names. If not generating Java code, this option has no effect.