Merge pull request #5010 from halseth/walletunlocker-unify-mobile
[mobile] Allow state API on mobile, simplify callback mechanism
This commit is contained in:
commit
173342a463
30
lnd.go
30
lnd.go
@ -54,31 +54,15 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WalletUnlockerAuthOptions returns a list of DialOptions that can be used to
|
|
||||||
// authenticate with the wallet unlocker service.
|
|
||||||
//
|
|
||||||
// NOTE: This should only be called after the WalletUnlocker listener has
|
|
||||||
// signaled it is ready.
|
|
||||||
func WalletUnlockerAuthOptions(cfg *Config) ([]grpc.DialOption, error) {
|
|
||||||
creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to read TLS cert: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a dial options array with the TLS credentials.
|
|
||||||
opts := []grpc.DialOption{
|
|
||||||
grpc.WithTransportCredentials(creds),
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdminAuthOptions returns a list of DialOptions that can be used to
|
// AdminAuthOptions returns a list of DialOptions that can be used to
|
||||||
// authenticate with the RPC server with admin capabilities.
|
// authenticate with the RPC server with admin capabilities.
|
||||||
|
// skipMacaroons=true should be set if we don't want to include macaroons with
|
||||||
|
// the auth options. This is needed for instance for the WalletUnlocker
|
||||||
|
// service, which must be usable also before macaroons are created.
|
||||||
//
|
//
|
||||||
// NOTE: This should only be called after the RPCListener has signaled it is
|
// NOTE: This should only be called after the RPCListener has signaled it is
|
||||||
// ready.
|
// ready.
|
||||||
func AdminAuthOptions(cfg *Config) ([]grpc.DialOption, error) {
|
func AdminAuthOptions(cfg *Config, skipMacaroons bool) ([]grpc.DialOption, error) {
|
||||||
creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
|
creds, err := credentials.NewClientTLSFromFile(cfg.TLSCertPath, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to read TLS cert: %v", err)
|
return nil, fmt.Errorf("unable to read TLS cert: %v", err)
|
||||||
@ -90,7 +74,7 @@ func AdminAuthOptions(cfg *Config) ([]grpc.DialOption, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the admin macaroon if macaroons are active.
|
// Get the admin macaroon if macaroons are active.
|
||||||
if !cfg.NoMacaroons {
|
if !skipMacaroons && !cfg.NoMacaroons {
|
||||||
// Load the adming macaroon file.
|
// Load the adming macaroon file.
|
||||||
macBytes, err := ioutil.ReadFile(cfg.AdminMacPath)
|
macBytes, err := ioutil.ReadFile(cfg.AdminMacPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -169,10 +153,6 @@ type ListenerWithSignal struct {
|
|||||||
// ListenerCfg is a wrapper around custom listeners that can be passed to lnd
|
// ListenerCfg is a wrapper around custom listeners that can be passed to lnd
|
||||||
// when calling its main method.
|
// when calling its main method.
|
||||||
type ListenerCfg struct {
|
type ListenerCfg struct {
|
||||||
// WalletUnlocker can be set to the listener to use for the wallet
|
|
||||||
// unlocker. If nil a regular network listener will be created.
|
|
||||||
WalletUnlocker *ListenerWithSignal
|
|
||||||
|
|
||||||
// RPCListener can be set to the listener to use for the RPC server. If
|
// RPCListener can be set to the listener to use for the RPC server. If
|
||||||
// nil a regular network listener will be created.
|
// nil a regular network listener will be created.
|
||||||
RPCListener *ListenerWithSignal
|
RPCListener *ListenerWithSignal
|
||||||
|
@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
ARG PROTOC_GEN_VERSION
|
ARG PROTOC_GEN_VERSION
|
||||||
ARG GRPC_GATEWAY_VERSION
|
ARG GRPC_GATEWAY_VERSION
|
||||||
|
|
||||||
ENV FALAFEL_VERSION="v0.7.1"
|
ENV FALAFEL_VERSION="v0.8.1"
|
||||||
ENV GOCACHE=/tmp/build/.cache
|
ENV GOCACHE=/tmp/build/.cache
|
||||||
ENV GOMODCACHE=/tmp/build/.modcache
|
ENV GOMODCACHE=/tmp/build/.modcache
|
||||||
|
|
||||||
|
@ -3,29 +3,34 @@
|
|||||||
package lndmobile
|
package lndmobile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
flags "github.com/jessevdk/go-flags"
|
flags "github.com/jessevdk/go-flags"
|
||||||
"github.com/lightningnetwork/lnd"
|
"github.com/lightningnetwork/lnd"
|
||||||
"github.com/lightningnetwork/lnd/signal"
|
"github.com/lightningnetwork/lnd/signal"
|
||||||
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// lndStarted will be used atomically to ensure only a singel lnd instance is
|
||||||
|
// attempted to be started at once.
|
||||||
|
var lndStarted int32
|
||||||
|
|
||||||
// Start starts lnd in a new goroutine.
|
// Start starts lnd in a new goroutine.
|
||||||
//
|
//
|
||||||
// extraArgs can be used to pass command line arguments to lnd that will
|
// extraArgs can be used to pass command line arguments to lnd that will
|
||||||
// override what is found in the config file. Example:
|
// override what is found in the config file. Example:
|
||||||
// extraArgs = "--bitcoin.testnet --lnddir=\"/tmp/folder name/\" --profile=5050"
|
// extraArgs = "--bitcoin.testnet --lnddir=\"/tmp/folder name/\" --profile=5050"
|
||||||
//
|
//
|
||||||
// The unlockerReady callback is called when the WalletUnlocker service is
|
// The rpcReady is called lnd is ready to accept RPC calls.
|
||||||
// ready, and rpcReady is called after the wallet has been unlocked and lnd is
|
|
||||||
// ready to accept RPC calls.
|
|
||||||
//
|
//
|
||||||
// NOTE: On mobile platforms the '--lnddir` argument should be set to the
|
// NOTE: On mobile platforms the '--lnddir` argument should be set to the
|
||||||
// current app directory in order to ensure lnd has the permissions needed to
|
// current app directory in order to ensure lnd has the permissions needed to
|
||||||
// write to it.
|
// write to it.
|
||||||
func Start(extraArgs string, unlockerReady, rpcReady Callback) {
|
func Start(extraArgs string, rpcReady Callback) {
|
||||||
// Split the argument string on "--" to get separated command line
|
// Split the argument string on "--" to get separated command line
|
||||||
// arguments.
|
// arguments.
|
||||||
var splitArgs []string
|
var splitArgs []string
|
||||||
@ -62,29 +67,37 @@ func Start(extraArgs string, unlockerReady, rpcReady Callback) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up channels that will be notified when the RPC servers are ready
|
// Set a channel that will be notified when the RPC server is ready to
|
||||||
// to accept calls.
|
// accept calls.
|
||||||
var (
|
var (
|
||||||
unlockerListening = make(chan struct{})
|
rpcListening = make(chan struct{})
|
||||||
rpcListening = make(chan struct{})
|
quit = make(chan struct{})
|
||||||
)
|
)
|
||||||
|
|
||||||
// We call the main method with the custom in-memory listeners called
|
// We call the main method with the custom in-memory listener called by
|
||||||
// by the mobile APIs, such that the grpc server will use these.
|
// the mobile APIs, such that the grpc server will use it.
|
||||||
cfg := lnd.ListenerCfg{
|
cfg := lnd.ListenerCfg{
|
||||||
WalletUnlocker: &lnd.ListenerWithSignal{
|
|
||||||
Listener: walletUnlockerLis,
|
|
||||||
Ready: unlockerListening,
|
|
||||||
},
|
|
||||||
RPCListener: &lnd.ListenerWithSignal{
|
RPCListener: &lnd.ListenerWithSignal{
|
||||||
Listener: lightningLis,
|
Listener: lightningLis,
|
||||||
Ready: rpcListening,
|
Ready: rpcListening,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only support a single lnd instance at a time (singleton) for now,
|
||||||
|
// so we make sure to return immediately if it has already been
|
||||||
|
// started.
|
||||||
|
if !atomic.CompareAndSwapInt32(&lndStarted, 0, 1) {
|
||||||
|
err := errors.New("lnd already started")
|
||||||
|
rpcReady.OnError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Call the "real" main in a nested manner so the defers will properly
|
// Call the "real" main in a nested manner so the defers will properly
|
||||||
// be executed in the case of a graceful shutdown.
|
// be executed in the case of a graceful shutdown.
|
||||||
go func() {
|
go func() {
|
||||||
|
defer atomic.StoreInt32(&lndStarted, 0)
|
||||||
|
defer close(quit)
|
||||||
|
|
||||||
if err := lnd.Main(
|
if err := lnd.Main(
|
||||||
loadedConfig, cfg, shutdownInterceptor,
|
loadedConfig, cfg, shutdownInterceptor,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
@ -98,40 +111,37 @@ func Start(extraArgs string, unlockerReady, rpcReady Callback) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Finally we start two go routines that will call the provided
|
// By default we'll apply the admin auth options, which will include
|
||||||
// callbacks when the RPC servers are ready to accept calls.
|
// macaroons.
|
||||||
go func() {
|
setDefaultDialOption(
|
||||||
<-unlockerListening
|
func() ([]grpc.DialOption, error) {
|
||||||
|
return lnd.AdminAuthOptions(loadedConfig, false)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// We must set the TLS certificates in order to properly
|
// For the WalletUnlocker and StateService, the macaroons might not be
|
||||||
// authenticate with the wallet unlocker service.
|
// available yet when called, so we use a more restricted set of
|
||||||
auth, err := lnd.WalletUnlockerAuthOptions(loadedConfig)
|
// options that don't include them.
|
||||||
if err != nil {
|
setWalletUnlockerDialOption(
|
||||||
unlockerReady.OnError(err)
|
func() ([]grpc.DialOption, error) {
|
||||||
|
return lnd.AdminAuthOptions(loadedConfig, true)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setStateDialOption(
|
||||||
|
func() ([]grpc.DialOption, error) {
|
||||||
|
return lnd.AdminAuthOptions(loadedConfig, true)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Finally we start a go routine that will call the provided callback
|
||||||
|
// when the RPC server is ready to accept calls.
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-rpcListening:
|
||||||
|
case <-quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the auth options to the listener's dial options.
|
|
||||||
addWalletUnlockerLisDialOption(auth...)
|
|
||||||
|
|
||||||
unlockerReady.OnResponse([]byte{})
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
<-rpcListening
|
|
||||||
|
|
||||||
// Now that the RPC server is ready, we can get the needed
|
|
||||||
// authentication options, and add them to the global dial
|
|
||||||
// options.
|
|
||||||
auth, err := lnd.AdminAuthOptions(loadedConfig)
|
|
||||||
if err != nil {
|
|
||||||
rpcReady.OnError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the auth options to the listener's dial options.
|
|
||||||
addLightningLisDialOption(auth...)
|
|
||||||
|
|
||||||
rpcReady.OnResponse([]byte{})
|
rpcReady.OnResponse([]byte{})
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ then
|
|||||||
version="v$($falafel -v)"
|
version="v$($falafel -v)"
|
||||||
if [ $version != $falafelVersion ]
|
if [ $version != $falafelVersion ]
|
||||||
then
|
then
|
||||||
echo "falafel version $falafelVersion required"
|
echo "falafel version $falafelVersion required, had $version"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "Using plugin $falafel $version"
|
echo "Using plugin $falafel $version"
|
||||||
@ -33,13 +33,13 @@ target_pkg="github.com/lightningnetwork/lnd/lnrpc"
|
|||||||
|
|
||||||
# A mapping from grpc service to name of the custom listeners. The grpc server
|
# A mapping from grpc service to name of the custom listeners. The grpc server
|
||||||
# must be configured to listen on these.
|
# must be configured to listen on these.
|
||||||
listeners="lightning=lightningLis walletunlocker=walletUnlockerLis"
|
listeners="lightning=lightningLis walletunlocker=lightningLis state=lightningLis"
|
||||||
|
|
||||||
# Set to 1 to create boiler plate grpc client code and listeners. If more than
|
# Set to 1 to create boiler plate grpc client code and listeners. If more than
|
||||||
# one proto file is being parsed, it should only be done once.
|
# one proto file is being parsed, it should only be done once.
|
||||||
mem_rpc=1
|
mem_rpc=1
|
||||||
|
|
||||||
PROTOS="rpc.proto walletunlocker.proto"
|
PROTOS="rpc.proto walletunlocker.proto stateservice.proto"
|
||||||
|
|
||||||
opts="package_name=$pkg,target_package=$target_pkg,listeners=$listeners,mem_rpc=$mem_rpc"
|
opts="package_name=$pkg,target_package=$target_pkg,listeners=$listeners,mem_rpc=$mem_rpc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user