github.com/decred/dcrlnd@v0.7.6/chainreg/chainregistry.go (about) 1 package chainreg 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "io/ioutil" 7 "net" 8 "os" 9 "strings" 10 "sync" 11 12 "github.com/decred/dcrd/chaincfg/chainhash" 13 "github.com/decred/dcrd/rpcclient/v8" 14 "github.com/decred/dcrlnd/blockcache" 15 "github.com/decred/dcrlnd/chainntnfs" 16 "github.com/decred/dcrlnd/chainntnfs/dcrdnotify" 17 "github.com/decred/dcrlnd/chainntnfs/dcrwnotify" 18 "github.com/decred/dcrlnd/chainntnfs/remotedcrwnotify" 19 "github.com/decred/dcrlnd/channeldb" 20 "github.com/decred/dcrlnd/htlcswitch" 21 "github.com/decred/dcrlnd/input" 22 "github.com/decred/dcrlnd/keychain" 23 "github.com/decred/dcrlnd/kvdb" 24 "github.com/decred/dcrlnd/lncfg" 25 "github.com/decred/dcrlnd/lnwallet" 26 "github.com/decred/dcrlnd/lnwallet/chainfee" 27 "github.com/decred/dcrlnd/lnwire" 28 "github.com/decred/dcrlnd/routing/chainview" 29 "github.com/decred/dcrlnd/walletunlocker" 30 ) 31 32 // Config houses necessary fields that a chainControl instance needs to 33 // function. 34 type Config struct { 35 // Decred defines the settings for the Decred chain. 36 Decred *lncfg.Chain 37 38 // PrimaryChain is a function that returns our primary chain via its 39 // ChainCode. 40 PrimaryChain func() ChainCode 41 42 // HeightHintCacheQueryDisable is a boolean that disables height hint 43 // queries if true. 44 HeightHintCacheQueryDisable bool 45 46 // DcrdMode defines settings for connecting to a dcrd instance. 47 DcrdMode *lncfg.DcrdConfig 48 49 // DcrwMode defines settings for connecting to a dcrwallet instance. 50 DcrwMode *lncfg.DcrwalletConfig 51 52 // FullDB is the full DB (the parent of ChanStateDB). 53 FullDB *channeldb.DB 54 55 // HeightHintDB is a pointer to the database that stores the height 56 // hints. 57 HeightHintDB kvdb.Backend 58 59 // ChanStateDB is a pointer to the database that stores the channel 60 // state. 61 ChanStateDB *channeldb.ChannelStateDB 62 63 // BlockCache is the main cache for storing block information. 64 BlockCache *blockcache.BlockCache 65 66 // WalletUnlockParams are the parameters that were used for unlocking 67 // the main wallet. 68 WalletUnlockParams *walletunlocker.WalletUnlockParams 69 70 // ActiveNetParams details the current chain we are on. 71 ActiveNetParams DecredNetParams 72 73 // FeeURL defines the URL for fee estimation we will use. This field is 74 // optional. 75 FeeURL string 76 77 // Dialer is a function closure that will be used to establish outbound 78 // TCP connections to chain network peers in the event of a pruned block being 79 // requested. 80 Dialer func(string) (net.Conn, error) 81 } 82 83 const ( 84 // DefaultDecredMinHTLCInMAtoms is the default smallest value htlc this 85 // node will accept. This value is proposed in the channel open 86 // sequence and cannot be changed during the life of the channel. 87 // 88 // All forwarded payments are subjected to the min htlc constraint of 89 // the routing policy of the outgoing channel. This implicitly controls 90 // the minimum htlc value on the incoming channel too. 91 DefaultDecredMinHTLCInMAtoms = lnwire.MilliAtom(1000) 92 93 // DefaultDecredMinHTLCOutMAtoms is the default minimum htlc value that 94 // we require for sending out htlcs. Our channel peer may have a lower 95 // min htlc channel parameter, but we - by default - don't forward 96 // anything under the value defined here. 97 DefaultDecredMinHTLCOutMAtoms = lnwire.MilliAtom(1000) 98 99 // DefaultDecredBaseFeeMAtoms is the default forwarding base fee. 100 DefaultDecredBaseFeeMAtoms = lnwire.MilliAtom(1000) 101 102 // DefaultDecredFeeRate is the default forwarding fee rate. 103 DefaultDecredFeeRate = lnwire.MilliAtom(1) 104 105 // DefaultDecredTimeLockDelta is the default forwarding time lock 106 // delta. 107 DefaultDecredTimeLockDelta = 80 108 109 // DefaultDecredStaticFeePerKB is the fee rate of 10000 atom/kB 110 DefaultDecredStaticFeePerKB = chainfee.AtomPerKByte(1e4) 111 112 // DefaultDecredStaticMinRelayFeeRate is the min relay fee used for 113 // static estimators. 114 DefaultDecredStaticMinRelayFeeRate = chainfee.FeePerKBFloor 115 ) 116 117 // PartialChainControl contains all the primary interfaces of the chain control 118 // that can be purely constructed from the global configuration. No wallet 119 // instance is required for constructing this partial state. 120 type PartialChainControl struct { 121 // Cfg is the configuration that was used to create the partial chain 122 // control. 123 Cfg *Config 124 125 // HealthCheck is a function which can be used to send a low-cost, fast 126 // query to the chain backend to ensure we still have access to our 127 // node. 128 HealthCheck func() error 129 130 // FeeEstimator is used to estimate an optimal fee for transactions 131 // important to us. 132 FeeEstimator chainfee.Estimator 133 134 // ChainNotifier is used to receive blockchain events that we are 135 // interested in. 136 ChainNotifier chainntnfs.ChainNotifier 137 138 // ChainView is used in the router for maintaining an up-to-date graph. 139 ChainView chainview.FilteredChainView 140 141 // RoutingPolicy is the routing policy we have decided to use. 142 RoutingPolicy htlcswitch.ForwardingPolicy 143 144 // MinHtlcIn is the minimum HTLC we will accept. 145 MinHtlcIn lnwire.MilliAtom 146 147 // ChannelConstraints is the set of default constraints that will be 148 // used for any incoming or outgoing channel reservation requests. 149 ChannelConstraints channeldb.ChannelConstraints 150 151 // RPCConfig is the config to the remote dcrd instance when using a 152 // sync mode that requires it. 153 RPCConfig *rpcclient.ConnConfig 154 } 155 156 // ChainControl couples the three primary interfaces lnd utilizes for a 157 // particular chain together. A single ChainControl instance will exist for all 158 // the chains lnd is currently active on. 159 type ChainControl struct { 160 // PartialChainControl is the part of the chain control that was 161 // initialized purely from the configuration and doesn't contain any 162 // wallet related elements. 163 *PartialChainControl 164 165 // ChainIO represents an abstraction over a source that can query the 166 // blockchain. 167 ChainIO lnwallet.BlockChainIO 168 169 // Signer is used to provide signatures over things like transactions. 170 Signer input.Signer 171 172 // KeyRing represents a set of keys that we have the private keys to. 173 KeyRing keychain.SecretKeyRing 174 175 // Wc is an abstraction over some basic wallet commands. This base set 176 // of commands will be provided to the Wallet *LightningWallet raw 177 // pointer below. 178 Wc lnwallet.WalletController 179 180 // MsgSigner is used to sign arbitrary messages. 181 MsgSigner lnwallet.MessageSigner 182 183 // Wallet is our LightningWallet that also contains the abstract Wc 184 // above. This wallet handles all of the lightning operations. 185 Wallet *lnwallet.LightningWallet 186 } 187 188 // GenDefaultDcrChannelConstraints generates the default set of channel 189 // constraints that are to be used when funding a Decred channel. 190 func GenDefaultDcrConstraints() channeldb.ChannelConstraints { 191 dustLimit := lnwallet.DustLimitForSize(input.P2PKHPkScriptSize) 192 193 return channeldb.ChannelConstraints{ 194 DustLimit: dustLimit, 195 MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, 196 } 197 } 198 199 // NewPartialChainControl creates a new partial chain control that contains all 200 // the parts that can be purely constructed from the passed in global 201 // configuration and doesn't need any wallet instance yet. 202 func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { 203 // Set the RPC config from the "home" chain. Multi-chain isn't yet 204 // active, so we'll restrict usage to a particular chain for now. 205 log.Infof("Primary chain is set to: %v", cfg.PrimaryChain()) 206 207 cc := &PartialChainControl{ 208 Cfg: cfg, 209 } 210 211 switch cfg.PrimaryChain() { 212 case DecredChain: 213 cc.RoutingPolicy = htlcswitch.ForwardingPolicy{ 214 MinHTLCOut: cfg.Decred.MinHTLCOut, 215 BaseFee: cfg.Decred.BaseFee, 216 FeeRate: cfg.Decred.FeeRate, 217 TimeLockDelta: cfg.Decred.TimeLockDelta, 218 } 219 cc.MinHtlcIn = cfg.Decred.MinHTLCIn 220 cc.FeeEstimator = chainfee.NewStaticEstimator( 221 DefaultDecredStaticFeePerKB, 222 DefaultDecredStaticMinRelayFeeRate, 223 ) 224 default: 225 return nil, nil, fmt.Errorf("default routing policy for chain "+ 226 "%v is unknown", cfg.PrimaryChain()) 227 } 228 229 var err error 230 heightHintCacheConfig := chainntnfs.CacheConfig{ 231 QueryDisable: cfg.HeightHintCacheQueryDisable, 232 } 233 if cfg.HeightHintCacheQueryDisable { 234 log.Infof("Height Hint Cache Queries disabled") 235 } 236 237 // Initialize the height hint cache within the chain directory. 238 hintCache, err := chainntnfs.NewHeightHintCache( 239 heightHintCacheConfig, cfg.HeightHintDB, 240 ) 241 if err != nil { 242 return nil, nil, fmt.Errorf("unable to initialize height hint "+ 243 "cache: %v", err) 244 } 245 246 // When running in remote wallet mode, we only support running in dcrw 247 // mode (using the wallet for chain operations). 248 walletConn := cfg.WalletUnlockParams.Conn 249 wallet := cfg.WalletUnlockParams.Wallet 250 if walletConn != nil && cfg.Decred.Node != "dcrw" { 251 return nil, nil, fmt.Errorf("remote wallet mode only supports " + 252 "'node=dcrw' config") 253 } 254 255 // When running in embedded wallet mode with spv on, we only support 256 // running in dcrw mode. 257 if walletConn == nil && cfg.DcrwMode.SPV && cfg.Decred.Node != "dcrw" { 258 return nil, nil, fmt.Errorf("embedded wallet in SPV mode only " + 259 "supports 'node=dcrw' config") 260 } 261 262 // We only require a dcrd connection when running in embedded mode and 263 // not in SPV mode. 264 needsDcrd := walletConn == nil && !cfg.DcrwMode.SPV 265 if needsDcrd { 266 // Load dcrd's TLS cert for the RPC connection. If a raw cert 267 // was specified in the config, then we'll set that directly. 268 // Otherwise, we attempt to read the cert from the path 269 // specified in the config. 270 dcrdMode := cfg.DcrdMode 271 var rpcCert []byte 272 if dcrdMode.RawRPCCert != "" { 273 rpcCert, err = hex.DecodeString(dcrdMode.RawRPCCert) 274 if err != nil { 275 return nil, nil, err 276 } 277 } else { 278 certFile, err := os.Open(dcrdMode.RPCCert) 279 if err != nil { 280 return nil, nil, err 281 } 282 rpcCert, err = ioutil.ReadAll(certFile) 283 if err != nil { 284 return nil, nil, err 285 } 286 if err := certFile.Close(); err != nil { 287 return nil, nil, err 288 } 289 } 290 291 // If the specified host for the dcrd RPC server already 292 // has a port specified, then we use that directly. Otherwise, 293 // we assume the default port according to the selected chain 294 // parameters. 295 var dcrdHost string 296 if strings.Contains(dcrdMode.RPCHost, ":") { 297 dcrdHost = dcrdMode.RPCHost 298 } else { 299 dcrdHost = fmt.Sprintf("%v:%v", dcrdMode.RPCHost, 300 cfg.ActiveNetParams.RPCPort) 301 } 302 303 dcrdUser := dcrdMode.RPCUser 304 dcrdPass := dcrdMode.RPCPass 305 cc.RPCConfig = &rpcclient.ConnConfig{ 306 Host: dcrdHost, 307 Endpoint: "ws", 308 User: dcrdUser, 309 Pass: dcrdPass, 310 Certificates: rpcCert, 311 DisableTLS: false, 312 DisableConnectOnNew: true, 313 DisableAutoReconnect: false, 314 } 315 316 // Verify that the provided dcrd instance exists, is reachable, 317 // it's on the correct network and has the features required 318 // for dcrlnd to perform its work. 319 if err = checkDcrdNode(cfg.ActiveNetParams.Net, *cc.RPCConfig); err != nil { 320 log.Errorf("unable to use specified dcrd node: %v", 321 err) 322 return nil, nil, err 323 } 324 } 325 326 // Initialize the appopriate wallet controller (either the embedded 327 // dcrwallet or a remote one). 328 switch { 329 case walletConn != nil: 330 log.Info("Using the remote wallet for chain operations") 331 332 // Remote wallet mode currently always use the wallet for chain 333 // notifications and chain IO. 334 cc.ChainNotifier, err = remotedcrwnotify.New( 335 walletConn, cfg.ActiveNetParams.Params, hintCache, 336 hintCache, cfg.BlockCache, 337 ) 338 if err != nil { 339 return nil, nil, err 340 } 341 342 cc.ChainView, err = chainview.NewRemoteWalletFilteredChainView(walletConn, 343 cfg.BlockCache) 344 if err != nil { 345 log.Errorf("unable to create chain view: %v", err) 346 return nil, nil, err 347 } 348 349 case cfg.Decred.Node == "dcrw": 350 // Use the wallet itself for chain IO. 351 log.Info("Using the wallet for chain operations") 352 353 cc.ChainNotifier, err = dcrwnotify.New( 354 wallet, cfg.ActiveNetParams.Params, hintCache, 355 hintCache, cfg.BlockCache, 356 ) 357 if err != nil { 358 return nil, nil, err 359 } 360 361 cc.ChainView, err = chainview.NewDcrwalletFilteredChainView( 362 wallet, cfg.BlockCache, 363 ) 364 if err != nil { 365 log.Errorf("unable to create chain view: %v", err) 366 return nil, nil, err 367 } 368 369 case cfg.Decred.Node == "dcrd": 370 // Use the dcrd node for chain IO. 371 log.Info("Using dcrd for chain operations") 372 373 cc.ChainNotifier, err = dcrdnotify.New( 374 cc.RPCConfig, cfg.ActiveNetParams.Params, hintCache, 375 hintCache, cfg.BlockCache, 376 ) 377 if err != nil { 378 return nil, nil, err 379 } 380 381 // Finally, we'll create an instance of the default 382 // chain view to be used within the routing layer. 383 cc.ChainView, err = chainview.NewDcrdFilteredChainView(*cc.RPCConfig) 384 if err != nil { 385 log.Errorf("unable to create chain view: %v", err) 386 return nil, nil, err 387 } 388 389 // If we're not in simnet or regtest mode, then we'll 390 // attempt to use a proper fee estimator. 391 if !cfg.Decred.SimNet && !cfg.Decred.RegTest { 392 log.Infof("Initializing dcrd backed fee estimator") 393 394 // Finally, we'll re-initialize the fee estimator, as 395 // if we're using dcrd as a backend, then we can use 396 // live fee estimates, rather than a statically coded 397 // value. 398 // 399 // TODO(decred) Review if fallbackFeeRate should be higher than 400 // the default relay fee. 401 fallBackFeeRate := chainfee.AtomPerKByte(1e4) 402 cc.FeeEstimator, err = chainfee.NewDcrdEstimator( 403 *cc.RPCConfig, fallBackFeeRate, 404 ) 405 if err != nil { 406 return nil, nil, err 407 } 408 } 409 410 case cfg.Decred.Node == "nochainbackend": 411 backend := &NoChainBackend{} 412 413 cc.ChainNotifier = backend 414 cc.ChainView = backend 415 cc.FeeEstimator = backend 416 417 cc.HealthCheck = func() error { 418 return nil 419 } 420 421 default: 422 return nil, nil, fmt.Errorf("unknown sync mode") 423 } 424 425 // Override default fee estimator if an external service is specified. 426 if cfg.FeeURL != "" { 427 // Do not cache fees on regtest and simnet to make it easier to 428 // execute manual or automated test cases. 429 cacheFees := !cfg.Decred.RegTest && !cfg.Decred.SimNet 430 431 log.Infof("Using external fee estimator %v: cached=%v", 432 cfg.FeeURL, cacheFees) 433 434 cc.FeeEstimator = chainfee.NewWebAPIEstimator( 435 chainfee.SparseConfFeeSource{ 436 URL: cfg.FeeURL, 437 }, 438 !cacheFees, 439 ) 440 } 441 442 ccCleanup := func() { 443 if cc.FeeEstimator != nil { 444 if err := cc.FeeEstimator.Stop(); err != nil { 445 log.Errorf("Failed to stop feeEstimator: %v", 446 err) 447 } 448 } 449 } 450 451 // Start fee estimator. 452 if err := cc.FeeEstimator.Start(); err != nil { 453 return nil, nil, err 454 } 455 456 // Select the default channel constraints for the primary chain. 457 cc.ChannelConstraints = GenDefaultDcrConstraints() 458 459 return cc, ccCleanup, nil 460 } 461 462 // NewChainControl attempts to create a ChainControl instance according 463 // to the parameters in the passed configuration. Currently three 464 // branches of ChainControl instances exist: one backed by a running btcd 465 // full-node, another backed by a running bitcoind full-node, and the other 466 // backed by a running neutrino light client instance. When running with a 467 // neutrino light client instance, `neutrinoCS` must be non-nil. 468 func NewChainControl(walletConfig lnwallet.Config, 469 msgSigner lnwallet.MessageSigner, 470 pcc *PartialChainControl) (*ChainControl, func(), error) { 471 472 cc := &ChainControl{ 473 PartialChainControl: pcc, 474 MsgSigner: msgSigner, 475 Signer: walletConfig.Signer, 476 ChainIO: walletConfig.ChainIO, 477 Wc: walletConfig.WalletController, 478 KeyRing: walletConfig.SecretKeyRing, 479 } 480 481 ccCleanup := func() { 482 if cc.Wallet != nil { 483 if err := cc.Wallet.Shutdown(); err != nil { 484 log.Errorf("Failed to shutdown wallet: %v", err) 485 } 486 } 487 } 488 489 // Set the chain IO healthcheck. 490 // 491 // NOTE: in lnd this is done in NewPartialChainControl(). 492 pcc.HealthCheck = func() error { 493 _, _, err := cc.ChainIO.GetBestBlock() 494 return err 495 } 496 497 lnWallet, err := lnwallet.NewLightningWallet(walletConfig) 498 if err != nil { 499 err := fmt.Errorf("unable to create wallet: %v", err) 500 return nil, ccCleanup, err 501 } 502 if err := lnWallet.Startup(); err != nil { 503 err := fmt.Errorf("unable to start wallet: %v", err) 504 return nil, ccCleanup, err 505 } 506 507 log.Info("LightningWallet opened") 508 cc.Wallet = lnWallet 509 510 return cc, ccCleanup, nil 511 } 512 513 var ( 514 // decredTestnet3Genesis is the genesis hash of Decred's testnet3 515 // chain. 516 decredTestnet3Genesis = chainhash.Hash([chainhash.HashSize]byte{ 517 0xac, 0x9b, 0xa4, 0x34, 0xb6, 0xf7, 0x24, 0x9b, 518 0x96, 0x98, 0xd1, 0xfc, 0xec, 0x26, 0xd6, 0x08, 519 0x7e, 0x83, 0x58, 0xc8, 0x11, 0xc7, 0xe9, 0x22, 520 0xf4, 0xca, 0x18, 0x39, 0xe5, 0xdc, 0x49, 0xa6, 521 }) 522 523 // decredMainnetGenesis is the genesis hash of Decred's main chain. 524 decredMainnetGenesis = chainhash.Hash([chainhash.HashSize]byte{ 525 0x80, 0xd9, 0x21, 0x2b, 0xf4, 0xce, 0xb0, 0x66, 526 0xde, 0xd2, 0x86, 0x6b, 0x39, 0xd4, 0xed, 0x89, 527 0xe0, 0xab, 0x60, 0xf3, 0x35, 0xc1, 0x1d, 0xf8, 528 0xe7, 0xbf, 0x85, 0xd9, 0xc3, 0x5c, 0x8e, 0x29, 529 }) 530 531 // chainMap is a simple index that maps a chain's genesis hash to the 532 // ChainCode enum for that chain. 533 chainMap = map[chainhash.Hash]ChainCode{ 534 decredTestnet3Genesis: DecredChain, 535 536 decredMainnetGenesis: DecredChain, 537 } 538 539 // ChainDNSSeeds is a map of a chain's hash to the set of DNS seeds 540 // that will be use to bootstrap peers upon first startup. 541 // 542 // The first item in the array is the primary host we'll use to attempt 543 // the SRV lookup we require. If we're unable to receive a response 544 // over UDP, then we'll fall back to manual TCP resolution. The second 545 // item in the array is a special A record that we'll query in order to 546 // receive the IP address of the current authoritative DNS server for 547 // the network seed. 548 // 549 // TODO(roasbeef): extend and collapse these and chainparams.go into 550 // struct like chaincfg.Params 551 ChainDNSSeeds = map[chainhash.Hash][][2]string{ 552 // TODO(decred): Add actual decred DNS seeder addresses once 553 // they're up. 554 decredMainnetGenesis: nil, 555 decredTestnet3Genesis: nil, 556 } 557 ) 558 559 // ChainRegistry keeps track of the current chains 560 type ChainRegistry struct { 561 sync.RWMutex 562 563 activeChains map[ChainCode]*ChainControl 564 netParams map[ChainCode]*DecredNetParams 565 566 primaryChain ChainCode 567 } 568 569 // NewChainRegistry creates a new ChainRegistry. 570 func NewChainRegistry() *ChainRegistry { 571 return &ChainRegistry{ 572 activeChains: make(map[ChainCode]*ChainControl), 573 netParams: make(map[ChainCode]*DecredNetParams), 574 } 575 } 576 577 // RegisterChain assigns an active ChainControl instance to a target chain 578 // identified by its ChainCode. 579 func (c *ChainRegistry) RegisterChain(newChain ChainCode, cc *ChainControl) { 580 c.Lock() 581 c.activeChains[newChain] = cc 582 c.Unlock() 583 } 584 585 // LookupChain attempts to lookup an active ChainControl instance for the 586 // target chain. 587 func (c *ChainRegistry) LookupChain(targetChain ChainCode) (*ChainControl, bool) { 588 c.RLock() 589 cc, ok := c.activeChains[targetChain] 590 c.RUnlock() 591 return cc, ok 592 } 593 594 // LookupChainByHash attempts to look up an active ChainControl which 595 // corresponds to the passed genesis hash. 596 func (c *ChainRegistry) LookupChainByHash( 597 chainHash chainhash.Hash) (*ChainControl, bool) { 598 599 c.RLock() 600 defer c.RUnlock() 601 602 targetChain, ok := chainMap[chainHash] 603 if !ok { 604 return nil, ok 605 } 606 607 cc, ok := c.activeChains[targetChain] 608 return cc, ok 609 } 610 611 // RegisterPrimaryChain sets a target chain as the "home chain" for lnd. 612 func (c *ChainRegistry) RegisterPrimaryChain(cc ChainCode) { 613 c.Lock() 614 defer c.Unlock() 615 616 c.primaryChain = cc 617 } 618 619 // PrimaryChain returns the primary chain for this running lnd instance. The 620 // primary chain is considered the "home base" while the other registered 621 // chains are treated as secondary chains. 622 func (c *ChainRegistry) PrimaryChain() ChainCode { 623 c.RLock() 624 defer c.RUnlock() 625 626 return c.primaryChain 627 } 628 629 // ActiveChains returns a slice containing the active chains. 630 func (c *ChainRegistry) ActiveChains() []ChainCode { 631 c.RLock() 632 defer c.RUnlock() 633 634 chains := make([]ChainCode, 0, len(c.activeChains)) 635 for activeChain := range c.activeChains { 636 chains = append(chains, activeChain) 637 } 638 639 return chains 640 } 641 642 // NumActiveChains returns the total number of active chains. 643 func (c *ChainRegistry) NumActiveChains() uint32 { 644 c.RLock() 645 defer c.RUnlock() 646 647 return uint32(len(c.activeChains)) 648 }