Skip to content

Instantly share code, notes, and snippets.

@bumi
Created November 2, 2020 20:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bumi/e22b3e093c3d884cb6fe3d0c8f2fa668 to your computer and use it in GitHub Desktop.
Save bumi/e22b3e093c3d884cb6fe3d0c8f2fa668 to your computer and use it in GitHub Desktop.
This is an example on how to connect to the LND gRPC interface through tor
package main
import (
"context"
"crypto/x509"
"encoding/hex"
"fmt"
"log"
"net"
"time"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/macaroons"
"gopkg.in/macaroon.v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"github.com/cretz/bine/tor"
)
func main() {
log.Printf("Starting Tor")
// We'll give it 5 minutes to run the whole thing (way too much of course, usually about 20 seconds)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
t, err := tor.Start(ctx, nil)
if err != nil {
log.Fatal(err)
}
defer t.Close()
conn, client, err := startClient(ctx, t)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
resp, err := client.GetInfo(context.Background(), &lnrpc.GetInfoRequest{})
fmt.Printf("%+v\n", resp)
resp, err = client.GetInfo(context.Background(), &lnrpc.GetInfoRequest{})
fmt.Printf("%+v\n", resp)
}
func startClient(ctx context.Context, t *tor.Tor) (conn *grpc.ClientConn, client lnrpc.LightningClient, err error) {
address := ""
macaroonHex := ""
certHex := ""
// Wait at most a few minutes to connect to the service
connCtx, connCancel := context.WithTimeout(ctx, 3*time.Minute)
defer connCancel()
dialer, err := t.Dialer(connCtx, nil)
if err != nil {
return nil, nil, err
}
// Get credentials either from a hex string or a file
var creds credentials.TransportCredentials
// if a hex string is provided
cp := x509.NewCertPool()
cert, err := hex.DecodeString(certHex)
if err != nil {
return nil, nil, err
}
cp.AppendCertsFromPEM(cert)
creds = credentials.NewClientTLSFromCert(cp, "")
opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
}
macaroonData, err := hex.DecodeString(macaroonHex)
if err != nil {
return nil, nil, err
}
mac := &macaroon.Macaroon{}
if err := mac.UnmarshalBinary(macaroonData); err != nil {
return nil, nil, err
}
macCred := macaroons.NewMacaroonCredential(mac)
opts = append(opts, grpc.WithPerRPCCredentials(macCred))
opts = append(opts, grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
dialCtx, dialCancel := context.WithTimeout(ctx, timeout)
defer dialCancel()
return dialer.DialContext(dialCtx, "tcp", addr)
}))
conn, err = grpc.DialContext(connCtx, address, opts...)
if err != nil {
return nil, nil, err
}
client = lnrpc.NewLightningClient(conn)
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment