2019-05-01 02:43:08 +00:00
|
|
|
package lndclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd/lncfg"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
|
|
"github.com/lightningnetwork/lnd/macaroons"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/credentials"
|
|
|
|
macaroon "gopkg.in/macaroon.v2"
|
|
|
|
)
|
|
|
|
|
2019-05-31 06:28:17 +00:00
|
|
|
// BasicClientOption is a functional option argument that allows adding arbitrary
|
|
|
|
// lnd basic client configuration overrides, without forcing existing users of
|
|
|
|
// NewBasicClient to update their invocation. These are always processed in
|
|
|
|
// order, with later options overriding earlier ones.
|
|
|
|
type BasicClientOption func(*basicClientOptions)
|
|
|
|
|
|
|
|
// basicClientOptions is a set of options that can configure the lnd client
|
|
|
|
// returned by NewBasicClient.
|
|
|
|
type basicClientOptions struct {
|
|
|
|
macFilename string
|
|
|
|
}
|
|
|
|
|
|
|
|
// defaultBasicClientOptions returns a basicClientOptions set to lnd basic client
|
|
|
|
// defaults.
|
|
|
|
func defaultBasicClientOptions() *basicClientOptions {
|
|
|
|
return &basicClientOptions{
|
|
|
|
macFilename: defaultAdminMacaroonFilename,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MacFilename is a basic client option that sets the name of the macaroon file
|
|
|
|
// to use.
|
|
|
|
func MacFilename(macFilename string) BasicClientOption {
|
|
|
|
return func(bc *basicClientOptions) {
|
|
|
|
bc.macFilename = macFilename
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// applyBasicClientOptions updates a basicClientOptions set with functional
|
|
|
|
// options.
|
|
|
|
func (bc *basicClientOptions) applyBasicClientOptions(options ...BasicClientOption) {
|
|
|
|
for _, option := range options {
|
|
|
|
option(bc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-01 02:43:08 +00:00
|
|
|
// NewBasicClient creates a new basic gRPC client to lnd. We call this client
|
2019-05-31 06:28:17 +00:00
|
|
|
// "basic" as it falls back to expected defaults if the arguments aren't
|
|
|
|
// provided.
|
|
|
|
func NewBasicClient(lndHost, tlsPath, macDir, network string, basicOptions ...BasicClientOption) (
|
|
|
|
lnrpc.LightningClient, error) {
|
|
|
|
|
2019-05-01 02:43:08 +00:00
|
|
|
if tlsPath == "" {
|
|
|
|
tlsPath = defaultTLSCertPath
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the specified TLS certificate and build transport credentials
|
|
|
|
creds, err := credentials.NewClientTLSFromFile(tlsPath, "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a dial options array.
|
|
|
|
opts := []grpc.DialOption{
|
|
|
|
grpc.WithTransportCredentials(creds),
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:33:32 +00:00
|
|
|
if macDir == "" {
|
|
|
|
macDir = filepath.Join(
|
2019-05-01 02:43:08 +00:00
|
|
|
defaultLndDir, defaultDataDir, defaultChainSubDir,
|
2019-05-03 00:33:32 +00:00
|
|
|
"bitcoin", network,
|
2019-05-01 02:43:08 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-05-31 06:28:17 +00:00
|
|
|
// Starting with the set of default options, we'll apply any specified
|
|
|
|
// functional options to the basic client.
|
|
|
|
bco := defaultBasicClientOptions()
|
|
|
|
bco.applyBasicClientOptions(basicOptions...)
|
|
|
|
|
|
|
|
macPath := filepath.Join(macDir, bco.macFilename)
|
2019-05-03 00:33:32 +00:00
|
|
|
|
2019-05-01 02:43:08 +00:00
|
|
|
// Load the specified macaroon file.
|
|
|
|
macBytes, err := ioutil.ReadFile(macPath)
|
|
|
|
if err == nil {
|
|
|
|
// Only if file is found
|
|
|
|
mac := &macaroon.Macaroon{}
|
|
|
|
if err = mac.UnmarshalBinary(macBytes); err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to decode macaroon: %v",
|
|
|
|
err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we append the macaroon credentials to the dial options.
|
|
|
|
cred := macaroons.NewMacaroonCredential(mac)
|
|
|
|
opts = append(opts, grpc.WithPerRPCCredentials(cred))
|
2019-05-21 23:57:04 +00:00
|
|
|
opts = append(opts, grpc.WithDefaultCallOptions(maxMsgRecvSize))
|
2019-05-01 02:43:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We need to use a custom dialer so we can also connect to unix sockets
|
|
|
|
// and not just TCP addresses.
|
|
|
|
opts = append(
|
2020-01-03 13:01:31 +00:00
|
|
|
opts, grpc.WithContextDialer(
|
2019-05-01 02:43:08 +00:00
|
|
|
lncfg.ClientAddressDialer(defaultRPCPort),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
conn, err := grpc.Dial(lndHost, opts...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("unable to connect to RPC server: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return lnrpc.NewLightningClient(conn), nil
|
|
|
|
}
|