github.com/decred/dcrlnd@v0.7.6/subrpcserver_config.go (about)

     1  package dcrlnd
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/decred/dcrd/chaincfg/v3"
     8  	"github.com/decred/dcrlnd/autopilot"
     9  	"github.com/decred/dcrlnd/chainreg"
    10  	"github.com/decred/dcrlnd/channeldb"
    11  	"github.com/decred/dcrlnd/htlcswitch"
    12  	"github.com/decred/dcrlnd/invoices"
    13  	"github.com/decred/dcrlnd/lncfg"
    14  	"github.com/decred/dcrlnd/lnrpc/autopilotrpc"
    15  	"github.com/decred/dcrlnd/lnrpc/chainrpc"
    16  	"github.com/decred/dcrlnd/lnrpc/invoicesrpc"
    17  	"github.com/decred/dcrlnd/lnrpc/routerrpc"
    18  	"github.com/decred/dcrlnd/lnrpc/signrpc"
    19  	"github.com/decred/dcrlnd/lnrpc/walletrpc"
    20  	"github.com/decred/dcrlnd/lnrpc/watchtowerrpc"
    21  	"github.com/decred/dcrlnd/lnrpc/wtclientrpc"
    22  	"github.com/decred/dcrlnd/lnwire"
    23  	"github.com/decred/dcrlnd/macaroons"
    24  	"github.com/decred/dcrlnd/netann"
    25  	"github.com/decred/dcrlnd/routing"
    26  	"github.com/decred/dcrlnd/sweep"
    27  	"github.com/decred/dcrlnd/watchtower"
    28  	"github.com/decred/dcrlnd/watchtower/wtclient"
    29  	"github.com/decred/slog"
    30  )
    31  
    32  // subRPCServerConfigs is special sub-config in the main configuration that
    33  // houses the configuration for the optional sub-servers. These sub-RPC servers
    34  // are meant to house experimental new features that may eventually make it
    35  // into the main RPC server that lnd exposes. Special methods are present on
    36  // this struct to allow the main RPC server to create and manipulate the
    37  // sub-RPC servers in a generalized manner.
    38  type subRPCServerConfigs struct {
    39  	// SignRPC is a sub-RPC server that exposes signing of arbitrary inputs
    40  	// as a gRPC service.
    41  	SignRPC *signrpc.Config `group:"signrpc" namespace:"signrpc"`
    42  
    43  	// WalletKitRPC is a sub-RPC server that exposes functionality allowing
    44  	// a client to send transactions through a wallet, publish them, and
    45  	// also requests keys and addresses under control of the backing
    46  	// wallet.
    47  	WalletKitRPC *walletrpc.Config `group:"walletrpc" namespace:"walletrpc"`
    48  
    49  	// AutopilotRPC is a sub-RPC server that exposes methods on the running
    50  	// autopilot as a gRPC service.
    51  	AutopilotRPC *autopilotrpc.Config `group:"autopilotrpc" namespace:"autopilotrpc"`
    52  
    53  	// ChainRPC is a sub-RPC server that exposes functionality allowing a
    54  	// client to be notified of certain on-chain events (new blocks,
    55  	// confirmations, spends).
    56  	ChainRPC *chainrpc.Config `group:"chainrpc" namespace:"chainrpc"`
    57  
    58  	// InvoicesRPC is a sub-RPC server that exposes invoice related methods
    59  	// as a gRPC service.
    60  	InvoicesRPC *invoicesrpc.Config `group:"invoicesrpc" namespace:"invoicesrpc"`
    61  
    62  	// RouterRPC is a sub-RPC server the exposes functionality that allows
    63  	// clients to send payments on the network, and perform Lightning
    64  	// payment related queries such as requests for estimates of off-chain
    65  	// fees.
    66  	RouterRPC *routerrpc.Config `group:"routerrpc" namespace:"routerrpc"`
    67  
    68  	// WatchtowerRPC is a sub-RPC server that exposes functionality allowing
    69  	// clients to monitor and control their embedded watchtower.
    70  	WatchtowerRPC *watchtowerrpc.Config `group:"watchtowerrpc" namespace:"watchtowerrpc"`
    71  
    72  	// WatchtowerClientRPC is a sub-RPC server that exposes functionality
    73  	// that allows clients to interact with the active watchtower client
    74  	// instance within lnd in order to add, remove, list registered client
    75  	// towers, etc.
    76  	WatchtowerClientRPC *wtclientrpc.Config `group:"wtclientrpc" namespace:"wtclientrpc"`
    77  }
    78  
    79  // PopulateDependencies attempts to iterate through all the sub-server configs
    80  // within this struct, and populate the items it requires based on the main
    81  // configuration file, and the chain control.
    82  //
    83  // NOTE: This MUST be called before any callers are permitted to execute the
    84  // FetchConfig method.
    85  func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config, cc *chainreg.ChainControl,
    86  	networkDir string, macService *macaroons.Service,
    87  	atpl *autopilot.Manager,
    88  	invoiceRegistry *invoices.InvoiceRegistry,
    89  	htlcSwitch *htlcswitch.Switch,
    90  	activeNetParams *chaincfg.Params,
    91  	chanRouter *routing.ChannelRouter,
    92  	routerBackend *routerrpc.RouterBackend,
    93  	nodeSigner *netann.NodeSigner,
    94  	graphDB *channeldb.ChannelGraph,
    95  	chanStateDB *channeldb.ChannelStateDB,
    96  	sweeper *sweep.UtxoSweeper,
    97  	tower *watchtower.Standalone,
    98  	towerClient wtclient.Client,
    99  	anchorTowerClient wtclient.Client,
   100  	tcpResolver lncfg.TCPResolver,
   101  	genInvoiceFeatures func() *lnwire.FeatureVector,
   102  	genAmpInvoiceFeatures func() *lnwire.FeatureVector,
   103  	rpcLogger slog.Logger) error {
   104  
   105  	// First, we'll use reflect to obtain a version of the config struct
   106  	// that allows us to programmatically inspect its fields.
   107  	selfVal := extractReflectValue(s)
   108  	selfType := selfVal.Type()
   109  
   110  	numFields := selfVal.NumField()
   111  	for i := 0; i < numFields; i++ {
   112  		field := selfVal.Field(i)
   113  		fieldElem := field.Elem()
   114  		fieldName := selfType.Field(i).Name
   115  
   116  		ltndLog.Debugf("Populating dependencies for sub RPC "+
   117  			"server: %v", fieldName)
   118  
   119  		// If this sub-config doesn't actually have any fields, then we
   120  		// can skip it, as the build tag for it is likely off.
   121  		if fieldElem.NumField() == 0 {
   122  			continue
   123  		}
   124  		if !fieldElem.CanSet() {
   125  			continue
   126  		}
   127  
   128  		switch subCfg := field.Interface().(type) {
   129  		case *signrpc.Config:
   130  			subCfgValue := extractReflectValue(subCfg)
   131  
   132  			subCfgValue.FieldByName("MacService").Set(
   133  				reflect.ValueOf(macService),
   134  			)
   135  			subCfgValue.FieldByName("NetworkDir").Set(
   136  				reflect.ValueOf(networkDir),
   137  			)
   138  			subCfgValue.FieldByName("Signer").Set(
   139  				reflect.ValueOf(cc.Signer),
   140  			)
   141  			subCfgValue.FieldByName("KeyRing").Set(
   142  				reflect.ValueOf(cc.KeyRing),
   143  			)
   144  
   145  		case *walletrpc.Config:
   146  			subCfgValue := extractReflectValue(subCfg)
   147  
   148  			subCfgValue.FieldByName("NetworkDir").Set(
   149  				reflect.ValueOf(networkDir),
   150  			)
   151  			subCfgValue.FieldByName("MacService").Set(
   152  				reflect.ValueOf(macService),
   153  			)
   154  			subCfgValue.FieldByName("FeeEstimator").Set(
   155  				reflect.ValueOf(cc.FeeEstimator),
   156  			)
   157  			subCfgValue.FieldByName("Wallet").Set(
   158  				reflect.ValueOf(cc.Wallet),
   159  			)
   160  			subCfgValue.FieldByName("CoinSelectionLocker").Set(
   161  				reflect.ValueOf(cc.Wallet),
   162  			)
   163  			subCfgValue.FieldByName("KeyRing").Set(
   164  				reflect.ValueOf(cc.KeyRing),
   165  			)
   166  			subCfgValue.FieldByName("Sweeper").Set(
   167  				reflect.ValueOf(sweeper),
   168  			)
   169  			subCfgValue.FieldByName("Chain").Set(
   170  				reflect.ValueOf(cc.ChainIO),
   171  			)
   172  			subCfgValue.FieldByName("ChainParams").Set(
   173  				reflect.ValueOf(activeNetParams),
   174  			)
   175  
   176  		case *autopilotrpc.Config:
   177  			subCfgValue := extractReflectValue(subCfg)
   178  
   179  			subCfgValue.FieldByName("Manager").Set(
   180  				reflect.ValueOf(atpl),
   181  			)
   182  
   183  		case *chainrpc.Config:
   184  			subCfgValue := extractReflectValue(subCfg)
   185  
   186  			subCfgValue.FieldByName("NetworkDir").Set(
   187  				reflect.ValueOf(networkDir),
   188  			)
   189  			subCfgValue.FieldByName("MacService").Set(
   190  				reflect.ValueOf(macService),
   191  			)
   192  			subCfgValue.FieldByName("ChainNotifier").Set(
   193  				reflect.ValueOf(cc.ChainNotifier),
   194  			)
   195  
   196  		case *invoicesrpc.Config:
   197  			subCfgValue := extractReflectValue(subCfg)
   198  
   199  			subCfgValue.FieldByName("NetworkDir").Set(
   200  				reflect.ValueOf(networkDir),
   201  			)
   202  			subCfgValue.FieldByName("MacService").Set(
   203  				reflect.ValueOf(macService),
   204  			)
   205  			subCfgValue.FieldByName("InvoiceRegistry").Set(
   206  				reflect.ValueOf(invoiceRegistry),
   207  			)
   208  			subCfgValue.FieldByName("IsChannelActive").Set(
   209  				reflect.ValueOf(htlcSwitch.HasActiveLink),
   210  			)
   211  			subCfgValue.FieldByName("ChainParams").Set(
   212  				reflect.ValueOf(activeNetParams),
   213  			)
   214  			subCfgValue.FieldByName("NodeSigner").Set(
   215  				reflect.ValueOf(nodeSigner),
   216  			)
   217  			defaultDelta := cfg.Decred.TimeLockDelta
   218  			subCfgValue.FieldByName("DefaultCLTVExpiry").Set(
   219  				reflect.ValueOf(defaultDelta),
   220  			)
   221  			subCfgValue.FieldByName("GraphDB").Set(
   222  				reflect.ValueOf(graphDB),
   223  			)
   224  			subCfgValue.FieldByName("ChanStateDB").Set(
   225  				reflect.ValueOf(chanStateDB),
   226  			)
   227  			subCfgValue.FieldByName("GenInvoiceFeatures").Set(
   228  				reflect.ValueOf(genInvoiceFeatures),
   229  			)
   230  			subCfgValue.FieldByName("GenAmpInvoiceFeatures").Set(
   231  				reflect.ValueOf(genAmpInvoiceFeatures),
   232  			)
   233  
   234  		// RouterRPC isn't conditionally compiled and doesn't need to be
   235  		// populated using reflection.
   236  		case *routerrpc.Config:
   237  
   238  		case *watchtowerrpc.Config:
   239  			subCfgValue := extractReflectValue(subCfg)
   240  
   241  			subCfgValue.FieldByName("Active").Set(
   242  				reflect.ValueOf(tower != nil),
   243  			)
   244  			subCfgValue.FieldByName("Tower").Set(
   245  				reflect.ValueOf(tower),
   246  			)
   247  
   248  		case *wtclientrpc.Config:
   249  			subCfgValue := extractReflectValue(subCfg)
   250  
   251  			if towerClient != nil && anchorTowerClient != nil {
   252  				subCfgValue.FieldByName("Active").Set(
   253  					reflect.ValueOf(towerClient != nil),
   254  				)
   255  				subCfgValue.FieldByName("Client").Set(
   256  					reflect.ValueOf(towerClient),
   257  				)
   258  				subCfgValue.FieldByName("AnchorClient").Set(
   259  					reflect.ValueOf(anchorTowerClient),
   260  				)
   261  			}
   262  			subCfgValue.FieldByName("Resolver").Set(
   263  				reflect.ValueOf(tcpResolver),
   264  			)
   265  			subCfgValue.FieldByName("Log").Set(
   266  				reflect.ValueOf(rpcLogger),
   267  			)
   268  
   269  		default:
   270  			return fmt.Errorf("unknown field: %v, %T", fieldName,
   271  				cfg)
   272  		}
   273  	}
   274  
   275  	// Populate routerrpc dependencies.
   276  	s.RouterRPC.NetworkDir = networkDir
   277  	s.RouterRPC.MacService = macService
   278  	s.RouterRPC.Router = chanRouter
   279  	s.RouterRPC.RouterBackend = routerBackend
   280  
   281  	return nil
   282  }
   283  
   284  // FetchConfig attempts to locate an existing configuration file mapped to the
   285  // target sub-server. If we're unable to find a config file matching the
   286  // subServerName name, then false will be returned for the second parameter.
   287  //
   288  // NOTE: Part of the lnrpc.SubServerConfigDispatcher interface.
   289  func (s *subRPCServerConfigs) FetchConfig(subServerName string) (interface{}, bool) {
   290  	// First, we'll use reflect to obtain a version of the config struct
   291  	// that allows us to programmatically inspect its fields.
   292  	selfVal := extractReflectValue(s)
   293  
   294  	// Now that we have the value of the struct, we can check to see if it
   295  	// has an attribute with the same name as the subServerName.
   296  	configVal := selfVal.FieldByName(subServerName)
   297  
   298  	// We'll now ensure that this field actually exists in this value. If
   299  	// not, then we'll return false for the ok value to indicate to the
   300  	// caller that this field doesn't actually exist.
   301  	if !configVal.IsValid() {
   302  		return nil, false
   303  	}
   304  
   305  	configValElem := configVal.Elem()
   306  
   307  	// If a config of this type is found, it doesn't have any fields, then
   308  	// it's the same as if it wasn't present. This can happen if the build
   309  	// tag for the sub-server is inactive.
   310  	if configValElem.NumField() == 0 {
   311  		return nil, false
   312  	}
   313  
   314  	// At this pint, we know that the field is actually present in the
   315  	// config struct, so we can return it directly.
   316  	return configVal.Interface(), true
   317  }
   318  
   319  // extractReflectValue attempts to extract the value from an interface using
   320  // the reflect package. The resulting reflect.Value allows the caller to
   321  // programmatically examine and manipulate the underlying value.
   322  func extractReflectValue(instance interface{}) reflect.Value {
   323  	var val reflect.Value
   324  
   325  	// If the type of the instance is a pointer, then we need to deference
   326  	// the pointer one level to get its value. Otherwise, we can access the
   327  	// value directly.
   328  	if reflect.TypeOf(instance).Kind() == reflect.Ptr {
   329  		val = reflect.ValueOf(instance).Elem()
   330  	} else {
   331  		val = reflect.ValueOf(instance)
   332  	}
   333  
   334  	return val
   335  }