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 }