mirror of
https://github.com/lightninglabs/faraday.git
synced 2026-08-13 12:33:35 +02:00
multi: optionally connect faraday to a bitcoin node
Original chain code copied from: e3c34449484d7dc8d505a98ea275e510651d7c3d Co-authored-by: Oliver Gugger gugger@gmail.com
This commit is contained in:
parent
9a58df81c9
commit
bb0b82aaee
4 changed files with 185 additions and 8 deletions
135
chain/client.go
Normal file
135
chain/client.go
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package chain
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/btcjson"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/rpcclient"
|
||||
)
|
||||
|
||||
// BitcoinClient is an interface which represents a connection to a bitcoin
|
||||
// client.
|
||||
type BitcoinClient interface {
|
||||
// GetTxDetail looks up a transaction.
|
||||
GetTxDetail(txHash *chainhash.Hash) (*btcjson.TxRawResult, error)
|
||||
}
|
||||
|
||||
// BitcoinConfig defines exported config options for the connection to the
|
||||
// btcd/bitcoind backend.
|
||||
type BitcoinConfig struct {
|
||||
Host string `long:"host" description:"host:port of the bitcoind/btcd instance address"`
|
||||
User string `long:"user" description:"bitcoind/btcd user name"`
|
||||
Password string `long:"password" description:"bitcoind/btcd password"`
|
||||
HTTPPostMode bool `long:"httppostmode" description:"Use HTTP POST mode? bitcoind only supports this mode"`
|
||||
UseTLS bool `long:"usetls" description:"Use TLS to connect? bitcoind only supports non-TLS connections"`
|
||||
TLSPath string `long:"tlspath" description:"Path to btcd tls certificate, bitcoind only supports non-TLS connections"`
|
||||
}
|
||||
|
||||
// DefaultConfig is the default config that we use to
|
||||
var DefaultConfig = &BitcoinConfig{
|
||||
Host: "localhost:8332",
|
||||
UseTLS: false,
|
||||
HTTPPostMode: true,
|
||||
}
|
||||
|
||||
// bitcoinClient is a wrapper around the RPC connection to the chain backend
|
||||
// and allows transactions to be queried.
|
||||
type bitcoinClient struct {
|
||||
sync.Mutex
|
||||
|
||||
rpcClient *rpcclient.Client
|
||||
|
||||
// txDetailCache holds a cache of transactions we have previously looked
|
||||
// up.
|
||||
txDetailCache map[string]*btcjson.TxRawResult
|
||||
}
|
||||
|
||||
// GetTxDetail fetches a single transaction from the chain and returns it
|
||||
// in a format that contains more details, like the block hash it was included
|
||||
// in for example.
|
||||
func (c *bitcoinClient) GetTxDetail(txHash *chainhash.Hash) (
|
||||
*btcjson.TxRawResult, error) {
|
||||
|
||||
c.Lock()
|
||||
cachedTx, ok := c.txDetailCache[txHash.String()]
|
||||
c.Unlock()
|
||||
if ok {
|
||||
return cachedTx, nil
|
||||
}
|
||||
|
||||
tx, err := c.rpcClient.GetRawTransactionVerbose(txHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do not cache the transaction if it has not confirmed yet. If we do,
|
||||
// we won't ever lookup the confirmed transaction because it is already
|
||||
// cached.
|
||||
if tx.BlockHash == "" {
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
c.txDetailCache[txHash.String()] = tx
|
||||
c.Unlock()
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// NewBitcoinClient attempts to connect to a bitcoin rpcclient with the config
|
||||
// provided and returns a BitcoinClient wrapper which can be used to access the
|
||||
// chain connection.
|
||||
func NewBitcoinClient(cfg *BitcoinConfig) (BitcoinClient, error) {
|
||||
client, err := getBitcoinConn(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &bitcoinClient{
|
||||
rpcClient: client,
|
||||
txDetailCache: make(map[string]*btcjson.TxRawResult),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getBitcoinConn gets a bitcoin rpc client from the config details provided.
|
||||
func getBitcoinConn(cfg *BitcoinConfig) (*rpcclient.Client, error) {
|
||||
// In case we use TLS and a certificate argument is provided, we need to
|
||||
// read that file and provide it to the RPC connection as byte slice.
|
||||
var rpcCert []byte
|
||||
if cfg.UseTLS && cfg.TLSPath != "" {
|
||||
certFile, err := os.Open(cfg.TLSPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rpcCert, err = ioutil.ReadAll(certFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := certFile.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to bitcoin core RPC server using HTTP POST mode.
|
||||
connCfg := &rpcclient.ConnConfig{
|
||||
Host: cfg.Host,
|
||||
User: cfg.User,
|
||||
Pass: cfg.Password,
|
||||
HTTPPostMode: cfg.HTTPPostMode,
|
||||
DisableTLS: !cfg.UseTLS,
|
||||
Certificates: rpcCert,
|
||||
}
|
||||
|
||||
// Notice the notification parameter is nil since notifications are
|
||||
// not supported in HTTP POST mode.
|
||||
return rpcclient.New(connCfg, nil)
|
||||
}
|
||||
|
||||
// Stop closes the connection to the chain backend and should always be
|
||||
// called on cleanup.
|
||||
func (c *bitcoinClient) Stop() {
|
||||
c.rpcClient.Shutdown()
|
||||
}
|
||||
28
config.go
28
config.go
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/lightninglabs/faraday/chain"
|
||||
"github.com/lightningnetwork/lnd/build"
|
||||
)
|
||||
|
||||
|
|
@ -15,6 +16,10 @@ const (
|
|||
defaultMinimumMonitor = time.Hour * 24 * 7 * 4 // four weeks in hours
|
||||
defaultDebugLevel = "info"
|
||||
defaultRPCListen = "localhost:8465"
|
||||
|
||||
// By default we do not require connecting to a bitcoin node so that
|
||||
// we can serve basic functionality by default.
|
||||
defaultChainConn = false
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
|
|
@ -36,6 +41,9 @@ type Config struct {
|
|||
// Simnet is set to true when using bitcoind's regtest.
|
||||
Regtest bool `long:"regtest" description:"Use regtest"`
|
||||
|
||||
// ChainConn specifies whether to attempt connecting to a bitcoin backend.
|
||||
ChainConn bool `long:"connect_bitcoin" description:"Whether to attempt to connect to a backing bitcoin node. Some endpoints will not be available if this option is not enabled."`
|
||||
|
||||
// MinimumMonitored is the minimum amount of time that a channel must be monitored for before we consider it for termination.
|
||||
MinimumMonitored time.Duration `long:"min_monitored" description:"The minimum amount of time that a channel must be monitored for before recommending termination. Valid time units are {s, m, h}."`
|
||||
|
||||
|
|
@ -54,6 +62,9 @@ type Config struct {
|
|||
|
||||
// CORSOrigin specifies the CORS header that should be set on REST responses. No header is added if the value is empty.
|
||||
CORSOrigin string `long:"corsorigin" description:"The value to send in the Access-Control-Allow-Origin header. Header will be omitted if empty."`
|
||||
|
||||
// Bitcoin is the configuration required to connect to a bitcoin node.
|
||||
Bitcoin *chain.BitcoinConfig `group:"bitcoin" namespace:"bitcoin"`
|
||||
}
|
||||
|
||||
// DefaultConfig returns all default values for the Config struct.
|
||||
|
|
@ -64,6 +75,8 @@ func DefaultConfig() Config {
|
|||
MinimumMonitored: defaultMinimumMonitor,
|
||||
DebugLevel: defaultDebugLevel,
|
||||
RPCListen: defaultRPCListen,
|
||||
ChainConn: defaultChainConn,
|
||||
Bitcoin: chain.DefaultConfig,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +111,21 @@ func LoadConfig() (*Config, error) {
|
|||
return nil, fmt.Errorf("do not specify more than one network flag")
|
||||
}
|
||||
|
||||
// If the user has opted into connecting to a bitcoin backend, check
|
||||
// that we have a rpc user and password, and that tls path is set if
|
||||
// required.
|
||||
if config.ChainConn {
|
||||
if config.Bitcoin.User == "" || config.Bitcoin.Password == "" {
|
||||
return nil, fmt.Errorf("rpc user and password " +
|
||||
"required when chainconn is set")
|
||||
}
|
||||
|
||||
if config.Bitcoin.UseTLS && config.Bitcoin.TLSPath == "" {
|
||||
return nil, fmt.Errorf("bitcoin.tlspath required " +
|
||||
"when chainconn is set")
|
||||
}
|
||||
}
|
||||
|
||||
if err := build.ParseAndSetDebugLevels(config.DebugLevel, logWriter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
25
faraday.go
25
faraday.go
|
|
@ -4,6 +4,7 @@ package faraday
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/lightninglabs/faraday/chain"
|
||||
"github.com/lightninglabs/faraday/frdrpc"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightningnetwork/lnd/signal"
|
||||
|
|
@ -35,14 +36,22 @@ func Main() error {
|
|||
defer client.Close()
|
||||
|
||||
// Instantiate the faraday gRPC server.
|
||||
server := frdrpc.NewRPCServer(
|
||||
&frdrpc.Config{
|
||||
Lnd: client.LndServices,
|
||||
RPCListen: config.RPCListen,
|
||||
RESTListen: config.RESTListen,
|
||||
CORSOrigin: config.CORSOrigin,
|
||||
},
|
||||
)
|
||||
cfg := &frdrpc.Config{
|
||||
Lnd: client.LndServices,
|
||||
RPCListen: config.RPCListen,
|
||||
RESTListen: config.RESTListen,
|
||||
CORSOrigin: config.CORSOrigin,
|
||||
}
|
||||
|
||||
// If the client chose to connect to a bitcoin client, get one now.
|
||||
if config.ChainConn {
|
||||
cfg.BitcoinClient, err = chain.NewBitcoinClient(config.Bitcoin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
server := frdrpc.NewRPCServer(cfg)
|
||||
|
||||
// Catch intercept signals, then start the server.
|
||||
signal.Intercept()
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
|
||||
proxy "github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/lightninglabs/faraday/accounting"
|
||||
"github.com/lightninglabs/faraday/chain"
|
||||
"github.com/lightninglabs/faraday/fiat"
|
||||
"github.com/lightninglabs/faraday/recommend"
|
||||
"github.com/lightninglabs/faraday/revenue"
|
||||
|
|
@ -102,6 +103,10 @@ type Config struct {
|
|||
// CORSOrigin specifies the CORS header that should be set on REST
|
||||
// responses. No header is added if the value is empty.
|
||||
CORSOrigin string
|
||||
|
||||
// BitcoinClient is set if the client opted to connect to a bitcoin
|
||||
// backend, if not, it will be nil.
|
||||
BitcoinClient chain.BitcoinClient
|
||||
}
|
||||
|
||||
// NewRPCServer returns a server which will listen for rpc requests on the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue