Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mobile: v2 implementation #704

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ litcli-debug
# MacOS junk
.DS_Store

# Files from mobile build.
mobile/build
mobile/*_generated.go

itest/btcd-itest
itest/litd-itest
itest/lnd-itest
itest/itest.test
itest/.logs
itest/*.log
itest/*.log
41 changes: 41 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PKG := github.com/lightninglabs/lightning-terminal
MOBILE_PKG := $(PKG)/mobile
ESCPKG := github.com\/lightninglabs\/lightning-terminal
LND_PKG := github.com/lightningnetwork/lnd
LOOP_PKG := github.com/lightninglabs/loop
Expand All @@ -13,6 +14,13 @@ TOOLS_DIR := tools
GO_BIN := ${GOPATH}/bin
GOACC_BIN := $(GO_BIN)/go-acc
GOIMPORTS_BIN := $(GO_BIN)/gosimports
GOMOBILE_BIN := GO111MODULE=off $(GO_BIN)/gomobile

MOBILE_BUILD_DIR :=${GOPATH}/src/$(MOBILE_PKG)/build
IOS_BUILD_DIR := $(MOBILE_BUILD_DIR)/ios
IOS_BUILD := $(IOS_BUILD_DIR)/Litdmobile.xcframework
ANDROID_BUILD_DIR := $(MOBILE_BUILD_DIR)/android
ANDROID_BUILD := $(ANDROID_BUILD_DIR)/Litdmobile.aar

COMMIT := $(shell git describe --abbrev=40 --dirty --tags)
COMMIT_HASH := $(shell git rev-parse HEAD)
Expand Down Expand Up @@ -247,3 +255,36 @@ clean:
$(RM) ./litcli-debug
$(RM) ./litd-debug
$(RM) coverage.txt

# =============
# MOBILE
# =============
mobile-rpc:
@$(call print, "Creating mobile RPC from protos.")
cd ./litrpc; COMPILE_MOBILE=1 SUBSERVER_PREFIX=1 ./gen_protos_docker.sh

vendor:
@$(call print, "Re-creating vendor directory.")
rm -r vendor/; go mod vendor

apple: vendor mobile-rpc
@$(call print, "Building iOS and macOS cxframework ($(IOS_BUILD)).")
mkdir -p $(IOS_BUILD_DIR)
$(GOMOBILE_BIN) bind -target=ios,iossimulator,macos -tags="mobile $(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG)

ios: vendor mobile-rpc
@$(call print, "Building iOS cxframework ($(IOS_BUILD)).")
mkdir -p $(IOS_BUILD_DIR)
$(GOMOBILE_BIN) bind -target=ios,iossimulator -tags="mobile $(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG)

macos: vendor mobile-rpc
@$(call print, "Building macOS cxframework ($(IOS_BUILD)).")
mkdir -p $(IOS_BUILD_DIR)
$(GOMOBILE_BIN) bind -target=macos -tags="mobile $(RELEASE_LDFLAGS)" -v -o $(IOS_BUILD) $(MOBILE_PKG)

android: vendor mobile-rpc
@$(call print, "Building Android library ($(ANDROID_BUILD)).")
mkdir -p $(ANDROID_BUILD_DIR)
$(GOMOBILE_BIN) bind -target=android -androidapi 21 -tags="mobile $(LND_RELEASE_TAGS)" -v -o $(ANDROID_BUILD) $(MOBILE_PKG)

mobile: ios android
2 changes: 1 addition & 1 deletion cmd/litd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

// main starts the lightning-terminal application.
func main() {
err := terminal.New().Run()
err := terminal.New(nil, nil).Run()
var flagErr *flags.Error
isFlagErr := errors.As(err, &flagErr)
if err != nil && (!isFlagErr || flagErr.Type != flags.ErrHelp) {
Expand Down
9 changes: 6 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,9 @@ type Config struct {
LetsEncryptDir string `long:"letsencryptdir" description:"The directory where the Let's Encrypt library will store its key and certificate."`
LetsEncryptListen string `long:"letsencryptlisten" description:"The IP:port on which LiT will listen for Let's Encrypt challenges. Let's Encrypt will always try to contact on port 80. Often non-root processes are not allowed to bind to ports lower than 1024. This configuration option allows a different port to be used, but must be used in combination with port forwarding from port 80. This configuration can also be used to specify another IP address to listen on, for example an IPv6 address."`

TLSCertPath string `long:"tlscertpath" description:"Path to write the self signed TLS certificate for LiT's RPC and REST proxy service (if Let's Encrypt is not used). This only applies to the HTTPSListen port."`
TLSKeyPath string `long:"tlskeypath" description:"Path to write the self signed TLS private key for LiT's RPC and REST proxy service (if Let's Encrypt is not used). This only applies to the HTTPSListen port."`
TLSCertPath string `long:"tlscertpath" description:"Path to write the self signed TLS certificate for LiT's RPC and REST proxy service (if Let's Encrypt is not used). This only applies to the HTTPSListen port."`
TLSKeyPath string `long:"tlskeypath" description:"Path to write the self signed TLS private key for LiT's RPC and REST proxy service (if Let's Encrypt is not used). This only applies to the HTTPSListen port."`
TLSDisableAutofill bool `long:"tlsdisableautofill" description:"Do not include the interface IPs or the system hostname in TLS certificate"`

LitDir string `long:"lit-dir" description:"The main directory where LiT looks for its configuration file. If LiT is running in 'remote' lnd mode, this is also the directory where the TLS certificates and log files are stored by default."`
ConfigFile string `long:"configfile" description:"Path to LiT's configuration file."`
Expand Down Expand Up @@ -826,13 +827,15 @@ func buildTLSConfigForHttp2(config *Config) (*tls.Config, error) {
} else {
tlsCertPath := config.TLSCertPath
tlsKeyPath := config.TLSKeyPath
tlsDisableAutoFill := config.TLSDisableAutofill

if !lnrpc.FileExists(tlsCertPath) &&
!lnrpc.FileExists(tlsKeyPath) {

//TODO(kevin): make this a config option, not a hardcoded flag
certBytes, keyBytes, err := cert.GenCertPair(
defaultSelfSignedCertOrganization, nil, nil,
false, DefaultAutogenValidity,
tlsDisableAutoFill, DefaultAutogenValidity,
)
if err != nil {
return nil, fmt.Errorf("failed creating "+
Expand Down
1 change: 1 addition & 0 deletions litrpc/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ RUN cd /tmp \
&& go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@${PROTOC_GEN_GO_GRPC_VERSION} \
&& go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@${GRPC_GATEWAY_VERSION} \
&& go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@${GRPC_GATEWAY_VERSION} \
&& go install golang.org/x/tools/cmd/goimports@v0.1.7 \
&& go install github.com/lightninglabs/falafel@${FALAFEL_VERSION}

WORKDIR /build
Expand Down
8 changes: 7 additions & 1 deletion litrpc/gen_protos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@ popd
pushd autopilotserverrpc
format
generate no-rest
popd
popd

if [[ "$COMPILE_MOBILE" == "1" ]]; then
pushd mobile
./gen_bindings.sh $FALAFEL_VERSION
popd
fi
2 changes: 2 additions & 0 deletions litrpc/gen_protos_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ docker run \
--rm \
--user $UID:$UID \
-e UID=$UID \
-e COMPILE_MOBILE \
-e SUBSERVER_PREFIX \
-v "$DIR/../:/build" \
lit-protobuf-builder
239 changes: 239 additions & 0 deletions mobile/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
# Building mobile libraries

## Prerequisites

To build for iOS, you need to run macOS with either
[Command Line Tools](https://developer.apple.com/download/all/?q=command%20line%20tools)
or [Xcode](https://apps.apple.com/app/xcode/id497799835) installed.

To build for Android, you need either
[Android Studio](https://developer.android.com/studio) or
[Command Line Tools](https://developer.android.com/studio#downloads) installed, which in turn must be used to install [Android NDK](https://developer.android.com/ndk/).


### Go and Go mobile

First, follow the instructions to [install Go](https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md#building-a-development-version-from-source).

Then, install [Go mobile](https://github.com/golang/go/wiki/Mobile) and
initialize it:

```shell
⛰ go install golang.org/x/mobile/cmd/gomobile@latest
⛰ go mod download golang.org/x/mobile
⛰ gomobile init
```

### Docker

Install and run [Docker](https://www.docker.com/products/docker-desktop).

### Make

Check that `make` is available by running the following command without errors:

```shell
⛰ make --version
```

## Building the libraries

Note that `gomobile` only supports building projects from `$GOPATH` at this
point. However, with the introduction of Go modules, the source code files are
no longer installed there by default.

To be able to do so, we must turn off module and using the now deprecated
`go get` command before turning modules back on again.

```shell
⛰ go env -w GO111MODULE="off"
⛰ go get github.com/lightninglabs/lightning-terminal
⛰ go get golang.org/x/mobile/bind
⛰ go env -w GO111MODULE="on"
```

Finally, let’s change directory to the newly created lightning-terminal folder inside `$GOPATH`:

```shell
⛰ cd $GOPATH/src/github.com/lightninglabs/lightning-terminal
```

It is not recommended building from the master branch for mainnet. To checkout
the latest tagged release of Lightning Terminal, run

```shell
⛰ git checkout $(git describe --match "v[0-9]*" --abbrev=0)
```

### iOS

```shell
⛰ make ios
```

The Xcode framework file will be found in `mobile/build/ios/Litdmobile.xcframework`.

### Android

```shell
⛰ make android
```

The AAR library file will be found in `mobile/build/android/Litdmobile.aar`.

---
Tip: `make mobile` will build both iOS and Android libraries.

---

## Generating proto definitions

In order to call the methods in the generated library, the serialized proto for
the given RPC call must be provided. Similarly, the response will be a
serialized proto.

### iOS

In order to generate protobuf definitions for iOS, add `--swift_out=.` to the
first `protoc` invocation found in [ `gen_protos.sh` ](../lnrpc/gen_protos.sh).

Then, some changes to [Dockerfile](../lnrpc/Dockerfile) need to be done in
order to use the [Swift protobuf](https://github.com/apple/swift-protobuf)
plugin with protoc:

1. Replace the base image with `FROM swift:focal` so that Swift can be used.
2. `clang-format='1:7.0*'` is unavailable in Ubuntu Focal. Change that to
`clang-format='1:10.0*'`.
3. On the next line, install Go and set the environment variables by adding the
following commands:

```
RUN apt-get install -y wget \
&& wget -c https://golang.org/dl/go1.17.6.linux-amd64.tar.gz -O - \
| tar -xz -C /usr/local
ENV GOPATH=/go
ENV PATH=$PATH:/usr/local/go/bin:/go/bin
```

4. At the end of the file, just above `CMD`, add the following `RUN` command.
This will download and compile the latest tagged release of Swift protobuf.

```
RUN git clone https://github.com/apple/swift-protobuf.git \
&& cd swift-protobuf \
&& git checkout $(git describe --tags --abbrev=0) \
&& swift build -c release \
&& mv .build/release/protoc-gen-swift /bin
```

Finally, run `make rpc`.

Tip: The generated Swift files will be found in various folders. If you’d like
to move them to the same folder as the framework file, run

```shell
⛰ find . -name "*.swift" -print0 | xargs -0 -I {} mv {} mobile/build/ios
```

`Litdmobile.xcframework` and all Swift files should now be added to your Xcode
project. You will also need to add [Swift Protobuf](https://github.com/apple/swift-protobuf)
to your project to support the generated code.

### Android

#### First option:

In order to generate protobuf definitions for Android, add `--java_out=.`

to the first `protoc` invocation found in
[ `gen_protos.sh` ](../lnrpc/gen_protos.sh). Then, run `make rpc`.


#### Second option (preferable):

- You have to install the profobuf plugin to your Android application.
Please, follow this link https://github.com/google/protobuf-gradle-plugin.
- Add this line to your `app build.gradle` file.
```shell
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.17"
```
- Create a `proto` folder under the `main` folder.

![proto_folder](docs/proto_folder.png)

- Add `aar` file to libs folder.

- After that add these lines to your `module's` `build.gradle` file:

```shell
plugins {
id "com.google.protobuf"
}

android {
sourceSets {
main {
proto {

}
}
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.google.protobuf:protobuf-javalite:${rootProject.ext.javalite_version}"
}

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${rootProject.ext.protoc_version}"
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
}
}
}
}
```
- Then, copy all the proto files from `lnd/lnrpc` to your `proto` folder, saving the structure.
- Build the project and wait until you see the generated Java proto files in the `build` folder.


---
*Note:*

If Android Studio tells you that the `aar` file cannot be included into the `app-bundle`, this is a workaround:

1. Create a separate gradle module
2. Remove everything from there and leave only `aar` and `build.gradle`.

![separate_gradle_module](docs/separate_gradle_module.png)

3. Gradle file should contain only these lines:

```shell
configurations.maybeCreate("default")
artifacts.add("default", file('Litdmobile.aar'))
```

4. In `dependencies` add this line instead of depending on `libs` folder:
```shell
implementation project(":litdmobile", { "default" })
```
---

## Calling the API

In LND v0.15+ all API methods have prefixed the generated methods with the subserver name. This is required to support subservers with name conflicts.

eg. `QueryScores` is now `AutopilotQueryScores`. `GetBlockHeader` is now `NeutrinoKitGetBlockHeader`.

## API docs

- [LND gRPC API Reference](https://api.lightning.community)
- [LND Builder’s Guide](https://docs.lightning.engineering)
Loading