// Grpc interface to lnd package lndrpc import ( "fmt" "io/ioutil" "log" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/macaroons" macaroon "gopkg.in/macaroon.v2" "git.sp4ke.com/sp4ke/bit4sat/config" "github.com/lightningnetwork/lnd/lnrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) func fatal(err error) { log.Fatal(err) } func getClient() (lnrpc.LightningClient, func()) { conn := getClientConn() cleanUp := func() { conn.Close() } return lnrpc.NewLightningClient(conn), cleanUp } func getClientConn() *grpc.ClientConn { // Load the specified TLS certificate and build transport credentials // with it. creds, err := credentials.NewClientTLSFromFile(config.LndCertPath, "") if err != nil { fatal(err) } // Create a dial options array. opts := []grpc.DialOption{ grpc.WithTransportCredentials(creds), } // Load the specified macaroon file. macBytes, err := ioutil.ReadFile(config.LndAdminMacaroonPath) if err != nil { fatal(fmt.Errorf("unable to read macaroon path (check "+ "the network setting!): %v", err)) } mac := &macaroon.Macaroon{} if err = mac.UnmarshalBinary(macBytes); err != nil { fatal(fmt.Errorf("unable to decode macaroon: %v", err)) } macConstraints := []macaroons.Constraint{ // We add a time-based constraint to prevent replay of the // macaroon. It's good for 60 seconds by default to make up for // any discrepancy between client and server clocks, but leaking // the macaroon before it becomes invalid makes it possible for // an attacker to reuse the macaroon. In addition, the validity // time of the macaroon is extended by the time the server clock // is behind the client clock, or shortened by the time the // server clock is ahead of the client clock (or invalid // altogether if, in the latter case, this time is more than 60 // seconds). // TODO(aakselrod): add better anti-replay protection. macaroons.TimeoutConstraint(60), // Lock macaroon down to a specific IP address. //macaroons.IPLockConstraint(config.LockMacaroonIp), macaroons.IPLockConstraint(""), // ... Add more constraints if needed. } // Apply constraints to the macaroon. constrainedMac, err := macaroons.AddConstraints(mac, macConstraints...) if err != nil { fatal(err) } // Now we append the macaroon credentials to the dial options. cred := macaroons.NewMacaroonCredential(constrainedMac) opts = append(opts, grpc.WithPerRPCCredentials(cred)) // We need to use a custom dialer so we can also connect to unix sockets // and not just TCP addresses. opts = append( opts, grpc.WithDialer( lncfg.ClientAddressDialer(config.LndGrpcPort), ), ) conn, err := grpc.Dial(fmt.Sprintf("%s:%s", config.LndGrpcHost, config.LndGrpcPort), opts...) if err != nil { fatal(fmt.Errorf("unable to connect to RPC server: %v", err)) } return conn } func init() { log.Println("init grpc") }