Merge pull request #16 from lightningnetwork/chainnotifier-interface
Refactor the chainntfs package to accommodate future ChainNotifier implementations
This commit is contained in:
commit
124b8b026c
@ -1 +0,0 @@
|
|||||||
package chainntnfs
|
|
@ -7,13 +7,20 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/chainntfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/roasbeef/btcd/btcjson"
|
"github.com/roasbeef/btcd/btcjson"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
"github.com/roasbeef/btcrpcclient"
|
"github.com/roasbeef/btcrpcclient"
|
||||||
"github.com/roasbeef/btcutil"
|
"github.com/roasbeef/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// notifierType uniquely identifies this concrete implementation of the
|
||||||
|
// ChainNotifier interface.
|
||||||
|
notifierType = "btcd"
|
||||||
|
)
|
||||||
|
|
||||||
// BtcdNotifier implements the ChainNotifier interface using btcd's websockets
|
// BtcdNotifier implements the ChainNotifier interface using btcd's websockets
|
||||||
// notifications. Multiple concurrent clients are supported. All notifications
|
// notifications. Multiple concurrent clients are supported. All notifications
|
||||||
// are achieved via non-blocking sends on client channels.
|
// are achieved via non-blocking sends on client channels.
|
||||||
@ -42,10 +49,10 @@ type BtcdNotifier struct {
|
|||||||
// Ensure BtcdNotifier implements the ChainNotifier interface at compile time.
|
// Ensure BtcdNotifier implements the ChainNotifier interface at compile time.
|
||||||
var _ chainntnfs.ChainNotifier = (*BtcdNotifier)(nil)
|
var _ chainntnfs.ChainNotifier = (*BtcdNotifier)(nil)
|
||||||
|
|
||||||
// NewBtcdNotifier returns a new BtcdNotifier instance. This function assumes
|
// New returns a new BtcdNotifier instance. This function assumes the btcd node
|
||||||
// the btcd node detailed in the passed configuration is already running, and
|
// detailed in the passed configuration is already running, and
|
||||||
// willing to accept new websockets clients.
|
// willing to accept new websockets clients.
|
||||||
func NewBtcdNotifier(config *btcrpcclient.ConnConfig) (*BtcdNotifier, error) {
|
func New(config *btcrpcclient.ConnConfig) (*BtcdNotifier, error) {
|
||||||
notifier := &BtcdNotifier{
|
notifier := &BtcdNotifier{
|
||||||
notificationRegistry: make(chan interface{}),
|
notificationRegistry: make(chan interface{}),
|
||||||
|
|
||||||
@ -66,8 +73,8 @@ func NewBtcdNotifier(config *btcrpcclient.ConnConfig) (*BtcdNotifier, error) {
|
|||||||
OnRedeemingTx: notifier.onRedeemingTx,
|
OnRedeemingTx: notifier.onRedeemingTx,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable connecting to btcd within the btcrpcclient.New method. We defer
|
// Disable connecting to btcd within the btcrpcclient.New method. We
|
||||||
// establishing the connection to our .Start() method.
|
// defer establishing the connection to our .Start() method.
|
||||||
config.DisableConnectOnNew = true
|
config.DisableConnectOnNew = true
|
||||||
config.DisableAutoReconnect = false
|
config.DisableAutoReconnect = false
|
||||||
chainConn, err := btcrpcclient.New(config, ntfnCallbacks)
|
chainConn, err := btcrpcclient.New(config, ntfnCallbacks)
|
@ -1,17 +1,21 @@
|
|||||||
package btcdnotify
|
package btcdnotify
|
||||||
|
|
||||||
// confEntry...
|
// confEntry represents an entry in the min-confirmation heap. .
|
||||||
type confEntry struct {
|
type confEntry struct {
|
||||||
*confirmationsNotification
|
*confirmationsNotification
|
||||||
|
|
||||||
triggerHeight uint32
|
triggerHeight uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// confirmationHeap...
|
// confirmationHeap is a list of confEntries sorted according to nearest
|
||||||
|
// "confirmation" height.Each entry within the min-confirmation heap is sorted
|
||||||
|
// according to the smallest dleta from the current blockheight to the
|
||||||
|
// triggerHeight of the next entry confirmationHeap
|
||||||
type confirmationHeap struct {
|
type confirmationHeap struct {
|
||||||
items []*confEntry
|
items []*confEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newConfirmationHeap returns a new confirmationHeap with zero items.
|
||||||
func newConfirmationHeap() *confirmationHeap {
|
func newConfirmationHeap() *confirmationHeap {
|
||||||
var confItems []*confEntry
|
var confItems []*confEntry
|
||||||
return &confirmationHeap{confItems}
|
return &confirmationHeap{confItems}
|
40
chainntnfs/btcdnotify/driver.go
Normal file
40
chainntnfs/btcdnotify/driver.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package btcdnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
|
"github.com/roasbeef/btcrpcclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
// createNewNotifier creates a new instance of the ChainNotifier interface
|
||||||
|
// implemented by BtcdNotifier.
|
||||||
|
func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return nil, fmt.Errorf("incorrect number of arguments to .New(...), "+
|
||||||
|
"expected 1, instead passed %v", len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
config, ok := args[0].(*btcrpcclient.ConnConfig)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("first argument to btcdnotifier.New is " +
|
||||||
|
"incorrect, expected a *btcrpcclient.ConnConfig")
|
||||||
|
}
|
||||||
|
|
||||||
|
return New(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// init registers a driver for the BtcdNotifier concrete implementation of the
|
||||||
|
// chainntnfs.ChainNotifier interface.
|
||||||
|
func init() {
|
||||||
|
// Register the driver.
|
||||||
|
notifier := &chainntnfs.NotifierDriver{
|
||||||
|
NotifierType: notifierType,
|
||||||
|
New: createNewNotifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := chainntnfs.RegisterNotifier(notifier); err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to register notifier driver '%s': %v",
|
||||||
|
notifierType, err))
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,11 @@
|
|||||||
package chainntnfs
|
package chainntnfs
|
||||||
|
|
||||||
import "github.com/roasbeef/btcd/wire"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
)
|
||||||
|
|
||||||
// ChainNotifier represents a trusted source to receive notifications concerning
|
// ChainNotifier represents a trusted source to receive notifications concerning
|
||||||
// targeted events on the Bitcoin blockchain. The interface specification is
|
// targeted events on the Bitcoin blockchain. The interface specification is
|
||||||
@ -104,3 +109,74 @@ type BlockEpoch struct {
|
|||||||
type BlockEpochEvent struct {
|
type BlockEpochEvent struct {
|
||||||
Epochs chan *BlockEpoch // MUST be buffered.
|
Epochs chan *BlockEpoch // MUST be buffered.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotifierDriver represents a "driver" for a particular interface. A driver is
|
||||||
|
// indentified by a globally unique string identifier along with a 'New()'
|
||||||
|
// method which is responsible for initializing a particular ChainNotifier
|
||||||
|
// concrete implementation.
|
||||||
|
type NotifierDriver struct {
|
||||||
|
// NotifierType is a string which uniquely identifes the ChainNotifier
|
||||||
|
// that this driver, drives.
|
||||||
|
NotifierType string
|
||||||
|
|
||||||
|
// New creates a new instance of a concrete ChainNotifier
|
||||||
|
// implementation given a variadic set up arguments. The function takes
|
||||||
|
// a varidaic number of interface paramters in order to provide
|
||||||
|
// initialization flexibility, thereby accomodating several potential
|
||||||
|
// ChainNotifier implementations.
|
||||||
|
New func(args ...interface{}) (ChainNotifier, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
notifiers = make(map[string]*NotifierDriver)
|
||||||
|
registerMtx sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisteredNotifiers returns a slice of all currently registered notifiers.
|
||||||
|
//
|
||||||
|
// NOTE: This function is safe for concurrent access.
|
||||||
|
func RegisteredNotifiers() []*NotifierDriver {
|
||||||
|
registerMtx.Lock()
|
||||||
|
defer registerMtx.Unlock()
|
||||||
|
|
||||||
|
drivers := make([]*NotifierDriver, 0, len(notifiers))
|
||||||
|
for _, driver := range notifiers {
|
||||||
|
drivers = append(drivers, driver)
|
||||||
|
}
|
||||||
|
|
||||||
|
return drivers
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterNotifier registers a NotifierDriver which is capable of driving a
|
||||||
|
// concrete ChainNotifier interface. In the case that this driver has already
|
||||||
|
// been registered, an error is returned.
|
||||||
|
//
|
||||||
|
// NOTE: This function is safe for concurrent access.
|
||||||
|
func RegisterNotifier(driver *NotifierDriver) error {
|
||||||
|
registerMtx.Lock()
|
||||||
|
defer registerMtx.Unlock()
|
||||||
|
|
||||||
|
if _, ok := notifiers[driver.NotifierType]; ok {
|
||||||
|
return fmt.Errorf("notifier already registered")
|
||||||
|
}
|
||||||
|
|
||||||
|
notifiers[driver.NotifierType] = driver
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedNotifiers returns a slice of strings that represent the database
|
||||||
|
// drivers that have been registered and are therefore supported.
|
||||||
|
//
|
||||||
|
// NOTE: This function is safe for concurrent access.
|
||||||
|
func SupportedNotifiers() []string {
|
||||||
|
registerMtx.Lock()
|
||||||
|
defer registerMtx.Unlock()
|
||||||
|
|
||||||
|
supportedNotifiers := make([]string, 0, len(notifiers))
|
||||||
|
for driverName := range notifiers {
|
||||||
|
supportedNotifiers = append(supportedNotifiers, driverName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return supportedNotifiers
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
package btcdnotify
|
package chainntnfs_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/chainntfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
|
_ "github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
|
||||||
|
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/chaincfg"
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
"github.com/roasbeef/btcd/rpctest"
|
"github.com/roasbeef/btcd/rpctest"
|
||||||
@ -181,7 +183,7 @@ func testSpendNotification(miner *rpctest.Harness,
|
|||||||
notifier chainntnfs.ChainNotifier, t *testing.T) {
|
notifier chainntnfs.ChainNotifier, t *testing.T) {
|
||||||
|
|
||||||
// We'd like to test the spend notifiations for all
|
// We'd like to test the spend notifiations for all
|
||||||
// chainntnfs.ChainNotifier concrete implemenations.
|
// ChainNotifier concrete implemenations.
|
||||||
//
|
//
|
||||||
// To do so, we first create a new output to our test target
|
// To do so, we first create a new output to our test target
|
||||||
// address.
|
// address.
|
||||||
@ -286,15 +288,22 @@ var ntfnTests = []func(node *rpctest.Harness, notifier chainntnfs.ChainNotifier,
|
|||||||
testSpendNotification,
|
testSpendNotification,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): make test generic across all interfaces?
|
// TestInterfaces tests all registered interfaces with a unified set of tests
|
||||||
// * indeed!
|
// which excersie each of the required methods found within the ChainNotifier
|
||||||
// * requires interface implementation registration
|
// interface.
|
||||||
func TestBtcdNotifier(t *testing.T) {
|
//
|
||||||
|
// NOTE: In the future, when additional implementations of the ChainNotifier
|
||||||
|
// interface have been implemented, in order to ensure the new concrete
|
||||||
|
// implementation is automatically tested, two steps must be undertaken. First,
|
||||||
|
// one needs add a "non-captured" (_) import from the new sub-package. This
|
||||||
|
// import should trigger an init() method within the package which registeres
|
||||||
|
// the interface. Second, an additional case in the switch within the main loop
|
||||||
|
// below needs to be added which properly initializes the interface.
|
||||||
|
func TestInterfaces(t *testing.T) {
|
||||||
// Initialize the harness around a btcd node which will serve as our
|
// Initialize the harness around a btcd node which will serve as our
|
||||||
// dedicated miner to generate blocks, cause re-orgs, etc. We'll set
|
// dedicated miner to generate blocks, cause re-orgs, etc. We'll set up
|
||||||
// up this node with a chain length of 125, so we have plentyyy of BTC
|
// this node with a chain length of 125, so we have plentyyy of BTC to
|
||||||
// to play around with.
|
// play around with.
|
||||||
miner, err := rpctest.New(netParams, nil, nil)
|
miner, err := rpctest.New(netParams, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create mining node: %v", err)
|
t.Fatalf("unable to create mining node: %v", err)
|
||||||
@ -304,17 +313,30 @@ func TestBtcdNotifier(t *testing.T) {
|
|||||||
t.Fatalf("unable to set up mining node: %v", err)
|
t.Fatalf("unable to set up mining node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig := miner.RPCConfig()
|
rpcConfig := miner.RPCConfig()
|
||||||
notifier, err := NewBtcdNotifier(&nodeConfig)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create notifier: %v", err)
|
|
||||||
}
|
|
||||||
if err := notifier.Start(); err != nil {
|
|
||||||
t.Fatalf("unable to start notifier: %v", err)
|
|
||||||
}
|
|
||||||
defer notifier.Stop()
|
|
||||||
|
|
||||||
for _, ntfnTest := range ntfnTests {
|
var notifier chainntnfs.ChainNotifier
|
||||||
ntfnTest(miner, notifier, t)
|
for _, notifierDriver := range chainntnfs.RegisteredNotifiers() {
|
||||||
|
notifierType := notifierDriver.NotifierType
|
||||||
|
|
||||||
|
switch notifierType {
|
||||||
|
case "btcd":
|
||||||
|
notifier, err = notifierDriver.New(&rpcConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create %v notifier: %v",
|
||||||
|
notifierType, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := notifier.Start(); err != nil {
|
||||||
|
t.Fatalf("unable to start notifier %v: %v",
|
||||||
|
notifierType, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ntfnTest := range ntfnTests {
|
||||||
|
ntfnTest(miner, notifier, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
notifier.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -89,6 +89,7 @@ func newHtlcSwitch() *htlcSwitch {
|
|||||||
linkControl: make(chan interface{}),
|
linkControl: make(chan interface{}),
|
||||||
htlcPlex: make(chan *htlcPacket, htlcQueueSize),
|
htlcPlex: make(chan *htlcPacket, htlcQueueSize),
|
||||||
outgoingPayments: make(chan *htlcPacket, htlcQueueSize),
|
outgoingPayments: make(chan *htlcPacket, htlcQueueSize),
|
||||||
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
lnd.go
37
lnd.go
@ -14,9 +14,11 @@ import (
|
|||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/roasbeef/btcrpcclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -94,9 +96,29 @@ func lndMain() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create, and start the lnwallet, which handles the core payment channel
|
btcdHost := fmt.Sprintf("%v:%v", loadedConfig.RPCHost, activeNetParams.rpcPort)
|
||||||
// logic, and exposes control via proxy state machines.
|
btcdUser := loadedConfig.RPCUser
|
||||||
config := &lnwallet.Config{
|
btcdPass := loadedConfig.RPCPass
|
||||||
|
|
||||||
|
// TODO(roasbeef): parse config here and select chosen notifier instead
|
||||||
|
rpcConfig := &btcrpcclient.ConnConfig{
|
||||||
|
Host: btcdHost,
|
||||||
|
Endpoint: "ws",
|
||||||
|
User: btcdUser,
|
||||||
|
Pass: btcdPass,
|
||||||
|
Certificates: rpcCert,
|
||||||
|
DisableTLS: false,
|
||||||
|
DisableConnectOnNew: true,
|
||||||
|
DisableAutoReconnect: false,
|
||||||
|
}
|
||||||
|
notifier, err := btcdnotify.New(rpcConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create, and start the lnwallet, which handles the core payment
|
||||||
|
// channel logic, and exposes control via proxy state machines.
|
||||||
|
walletConfig := &lnwallet.Config{
|
||||||
PrivatePass: []byte("hello"),
|
PrivatePass: []byte("hello"),
|
||||||
DataDir: filepath.Join(loadedConfig.DataDir, "lnwallet"),
|
DataDir: filepath.Join(loadedConfig.DataDir, "lnwallet"),
|
||||||
RpcHost: fmt.Sprintf("%v:%v", rpcIP[0], activeNetParams.rpcPort),
|
RpcHost: fmt.Sprintf("%v:%v", rpcIP[0], activeNetParams.rpcPort),
|
||||||
@ -105,7 +127,7 @@ func lndMain() error {
|
|||||||
CACert: rpcCert,
|
CACert: rpcCert,
|
||||||
NetParams: activeNetParams.Params,
|
NetParams: activeNetParams.Params,
|
||||||
}
|
}
|
||||||
wallet, err := lnwallet.NewLightningWallet(config, chanDB)
|
wallet, err := lnwallet.NewLightningWallet(walletConfig, chanDB, notifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unable to create wallet: %v\n", err)
|
fmt.Printf("unable to create wallet: %v\n", err)
|
||||||
return err
|
return err
|
||||||
@ -124,12 +146,15 @@ func lndMain() error {
|
|||||||
defaultListenAddrs := []string{
|
defaultListenAddrs := []string{
|
||||||
net.JoinHostPort("", strconv.Itoa(loadedConfig.PeerPort)),
|
net.JoinHostPort("", strconv.Itoa(loadedConfig.PeerPort)),
|
||||||
}
|
}
|
||||||
server, err := newServer(defaultListenAddrs, wallet, chanDB)
|
server, err := newServer(defaultListenAddrs, notifier, wallet, chanDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
srvrLog.Errorf("unable to create server: %v\n", err)
|
srvrLog.Errorf("unable to create server: %v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
server.Start()
|
if err := server.Start(); err != nil {
|
||||||
|
srvrLog.Errorf("unable to create to start: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
addInterruptHandler(func() {
|
addInterruptHandler(func() {
|
||||||
ltndLog.Infof("Gracefully shutting down the server...")
|
ltndLog.Infof("Gracefully shutting down the server...")
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/fastsha256"
|
"github.com/btcsuite/fastsha256"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/chainntfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ import (
|
|||||||
// such as: uspv, btcwallet, Bitcoin Core, Electrum, etc. This interface then
|
// such as: uspv, btcwallet, Bitcoin Core, Electrum, etc. This interface then
|
||||||
// serves as a "base wallet", with Lightning Network awareness taking place at
|
// serves as a "base wallet", with Lightning Network awareness taking place at
|
||||||
// a "higher" level of abstraction. Essentially, an overlay wallet.
|
// a "higher" level of abstraction. Essentially, an overlay wallet.
|
||||||
// Implementors of this interface must closely adhere to the documented behavior
|
// Implementors of this interface must closely adhere to the documented
|
||||||
// of all interface methods in order to ensure identical behavior accross all
|
// behavior of all interface methods in order to ensure identical behavior
|
||||||
// concrete implementations.
|
// across all concrete implementations.
|
||||||
type WalletController interface {
|
type WalletController interface {
|
||||||
// ConfirmedBalance returns the sum of all the wallet's unspent outputs
|
// ConfirmedBalance returns the sum of all the wallet's unspent outputs
|
||||||
// that have at least confs confirmations. If confs is set to zero,
|
// that have at least confs confirmations. If confs is set to zero,
|
||||||
|
@ -9,8 +9,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/chainntfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/chainntfs/btcdnotify"
|
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/elkrem"
|
"github.com/lightningnetwork/lnd/elkrem"
|
||||||
"github.com/roasbeef/btcd/btcjson"
|
"github.com/roasbeef/btcd/btcjson"
|
||||||
@ -18,7 +17,6 @@ import (
|
|||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
"github.com/roasbeef/btcd/txscript"
|
"github.com/roasbeef/btcd/txscript"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
"github.com/roasbeef/btcrpcclient"
|
|
||||||
"github.com/roasbeef/btcutil"
|
"github.com/roasbeef/btcutil"
|
||||||
"github.com/roasbeef/btcutil/coinset"
|
"github.com/roasbeef/btcutil/coinset"
|
||||||
"github.com/roasbeef/btcutil/txsort"
|
"github.com/roasbeef/btcutil/txsort"
|
||||||
@ -234,8 +232,7 @@ type LightningWallet struct {
|
|||||||
// Used by in order to obtain notifications about funding transaction
|
// Used by in order to obtain notifications about funding transaction
|
||||||
// reaching a specified confirmation depth, and to catch
|
// reaching a specified confirmation depth, and to catch
|
||||||
// counterparty's broadcasting revoked commitment states.
|
// counterparty's broadcasting revoked commitment states.
|
||||||
// TODO(roasbeef): needs to be stripped out from wallet
|
chainNotifier chainntnfs.ChainNotifier
|
||||||
ChainNotifier chainntnfs.ChainNotifier
|
|
||||||
|
|
||||||
// The core wallet, all non Lightning Network specific interaction is
|
// The core wallet, all non Lightning Network specific interaction is
|
||||||
// proxied to the internal wallet.
|
// proxied to the internal wallet.
|
||||||
@ -279,7 +276,12 @@ type LightningWallet struct {
|
|||||||
// NewLightningWallet creates/opens and initializes a LightningWallet instance.
|
// NewLightningWallet creates/opens and initializes a LightningWallet instance.
|
||||||
// If the wallet has never been created (according to the passed dataDir), first-time
|
// If the wallet has never been created (according to the passed dataDir), first-time
|
||||||
// setup is executed.
|
// setup is executed.
|
||||||
func NewLightningWallet(config *Config, cdb *channeldb.DB) (*LightningWallet, error) {
|
//
|
||||||
|
// NOTE: The passed channeldb, and ChainNotifier should already be fully
|
||||||
|
// initialized/started before being passed as a function arugment.
|
||||||
|
func NewLightningWallet(config *Config, cdb *channeldb.DB,
|
||||||
|
notifier chainntnfs.ChainNotifier) (*LightningWallet, error) {
|
||||||
|
|
||||||
// Ensure the wallet exists or create it when the create flag is set.
|
// Ensure the wallet exists or create it when the create flag is set.
|
||||||
netDir := networkDir(config.DataDir, config.NetParams)
|
netDir := networkDir(config.DataDir, config.NetParams)
|
||||||
|
|
||||||
@ -344,26 +346,8 @@ func NewLightningWallet(config *Config, cdb *channeldb.DB) (*LightningWallet, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using the same authentication info, create a config for a second
|
|
||||||
// rpcclient which will be used by the current default chain
|
|
||||||
// notifier implemenation.
|
|
||||||
rpcConfig := &btcrpcclient.ConnConfig{
|
|
||||||
Host: config.RpcHost,
|
|
||||||
Endpoint: "ws",
|
|
||||||
User: config.RpcUser,
|
|
||||||
Pass: config.RpcPass,
|
|
||||||
Certificates: config.CACert,
|
|
||||||
DisableTLS: false,
|
|
||||||
DisableConnectOnNew: true,
|
|
||||||
DisableAutoReconnect: false,
|
|
||||||
}
|
|
||||||
chainNotifier, err := btcdnotify.NewBtcdNotifier(rpcConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &LightningWallet{
|
return &LightningWallet{
|
||||||
ChainNotifier: chainNotifier,
|
chainNotifier: notifier,
|
||||||
rpc: rpcc,
|
rpc: rpcc,
|
||||||
Wallet: wallet,
|
Wallet: wallet,
|
||||||
channelDB: cdb,
|
channelDB: cdb,
|
||||||
@ -393,17 +377,8 @@ func (l *LightningWallet) Startup() error {
|
|||||||
}
|
}
|
||||||
l.Start()
|
l.Start()
|
||||||
|
|
||||||
// Start the notification server. This is used so channel managment
|
// Pass the rpc client into the wallet so it can sync up to the
|
||||||
// goroutines can be notified when a funding transaction reaches a
|
// current main chain.
|
||||||
// sufficient number of confirmations, or when the input for the funding
|
|
||||||
// transaction is spent in an attempt at an uncooperative close by the
|
|
||||||
// counter party.
|
|
||||||
if err := l.ChainNotifier.Start(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass the rpc client into the wallet so it can sync up to the current
|
|
||||||
// main chain.
|
|
||||||
l.SynchronizeRPC(l.rpc)
|
l.SynchronizeRPC(l.rpc)
|
||||||
|
|
||||||
l.wg.Add(1)
|
l.wg.Add(1)
|
||||||
@ -426,8 +401,6 @@ func (l *LightningWallet) Shutdown() error {
|
|||||||
|
|
||||||
l.rpc.Shutdown()
|
l.rpc.Shutdown()
|
||||||
|
|
||||||
l.ChainNotifier.Stop()
|
|
||||||
|
|
||||||
close(l.quit)
|
close(l.quit)
|
||||||
l.wg.Wait()
|
l.wg.Wait()
|
||||||
return nil
|
return nil
|
||||||
@ -1251,7 +1224,7 @@ func (l *LightningWallet) handleChannelOpen(req *channelOpenMsg) {
|
|||||||
|
|
||||||
// Finally, create and officially open the payment channel!
|
// Finally, create and officially open the payment channel!
|
||||||
// TODO(roasbeef): CreationTime once tx is 'open'
|
// TODO(roasbeef): CreationTime once tx is 'open'
|
||||||
channel, _ := NewLightningChannel(l, l.ChainNotifier, l.channelDB,
|
channel, _ := NewLightningChannel(l, l.chainNotifier, l.channelDB,
|
||||||
res.partialState)
|
res.partialState)
|
||||||
|
|
||||||
res.chanOpen <- channel
|
res.chanOpen <- channel
|
||||||
@ -1266,7 +1239,7 @@ func (l *LightningWallet) openChannelAfterConfirmations(res *ChannelReservation)
|
|||||||
// transaction reaches `numConfs` confirmations.
|
// transaction reaches `numConfs` confirmations.
|
||||||
txid := res.fundingTx.TxSha()
|
txid := res.fundingTx.TxSha()
|
||||||
numConfs := uint32(res.numConfsToOpen)
|
numConfs := uint32(res.numConfsToOpen)
|
||||||
confNtfn, _ := l.ChainNotifier.RegisterConfirmationsNtfn(&txid, numConfs)
|
confNtfn, _ := l.chainNotifier.RegisterConfirmationsNtfn(&txid, numConfs)
|
||||||
|
|
||||||
walletLog.Infof("Waiting for funding tx (txid: %v) to reach %v confirmations",
|
walletLog.Infof("Waiting for funding tx (txid: %v) to reach %v confirmations",
|
||||||
txid, numConfs)
|
txid, numConfs)
|
||||||
@ -1293,7 +1266,7 @@ out:
|
|||||||
|
|
||||||
// Finally, create and officially open the payment channel!
|
// Finally, create and officially open the payment channel!
|
||||||
// TODO(roasbeef): CreationTime once tx is 'open'
|
// TODO(roasbeef): CreationTime once tx is 'open'
|
||||||
channel, _ := NewLightningChannel(l, l.ChainNotifier, l.channelDB,
|
channel, _ := NewLightningChannel(l, l.chainNotifier, l.channelDB,
|
||||||
res.partialState)
|
res.partialState)
|
||||||
res.chanOpen <- channel
|
res.chanOpen <- channel
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
|
"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/roasbeef/btcd/chaincfg"
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
"github.com/roasbeef/btcutil/txsort"
|
"github.com/roasbeef/btcutil/txsort"
|
||||||
@ -338,7 +339,15 @@ func createTestWallet(miningNode *rpctest.Harness, netParams *chaincfg.Params) (
|
|||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wallet, err := NewLightningWallet(config, cdb)
|
chainNotifier, err := btcdnotify.New(&rpcConfig)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
if err := chainNotifier.Start(); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := NewLightningWallet(config, cdb, chainNotifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
2
log.go
2
log.go
@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btclog"
|
"github.com/btcsuite/btclog"
|
||||||
"github.com/btcsuite/seelog"
|
"github.com/btcsuite/seelog"
|
||||||
"github.com/lightningnetwork/lnd/chainntfs"
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
)
|
)
|
||||||
|
5
peer.go
5
peer.go
@ -218,7 +218,7 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error {
|
|||||||
for _, dbChan := range chans {
|
for _, dbChan := range chans {
|
||||||
chanID := dbChan.ChanID
|
chanID := dbChan.ChanID
|
||||||
lnChan, err := lnwallet.NewLightningChannel(p.server.lnwallet,
|
lnChan, err := lnwallet.NewLightningChannel(p.server.lnwallet,
|
||||||
p.server.lnwallet.ChainNotifier, p.server.chanDB, dbChan)
|
p.server.chainNotifier, p.server.chanDB, dbChan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -673,8 +673,7 @@ func (p *peer) handleLocalClose(req *closeLinkReq) {
|
|||||||
// confirmation.
|
// confirmation.
|
||||||
go func() {
|
go func() {
|
||||||
// TODO(roasbeef): add param for num needed confs
|
// TODO(roasbeef): add param for num needed confs
|
||||||
notifier := p.server.lnwallet.ChainNotifier
|
confNtfn, err := p.server.chainNotifier.RegisterConfirmationsNtfn(txid, 1)
|
||||||
confNtfn, err := notifier.RegisterConfirmationsNtfn(txid, 1)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.err <- err
|
req.err <- err
|
||||||
return
|
return
|
||||||
|
70
server.go
70
server.go
@ -8,6 +8,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/btcsuite/fastsha256"
|
"github.com/btcsuite/fastsha256"
|
||||||
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lndc"
|
"github.com/lightningnetwork/lnd/lndc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
@ -40,9 +41,9 @@ type server struct {
|
|||||||
listeners []net.Listener
|
listeners []net.Listener
|
||||||
peers map[int32]*peer
|
peers map[int32]*peer
|
||||||
|
|
||||||
rpcServer *rpcServer
|
rpcServer *rpcServer
|
||||||
// TODO(roasbeef): add chan notifier also
|
chainNotifier chainntnfs.ChainNotifier
|
||||||
lnwallet *lnwallet.LightningWallet
|
lnwallet *lnwallet.LightningWallet
|
||||||
|
|
||||||
// TODO(roasbeef): add to constructor
|
// TODO(roasbeef): add to constructor
|
||||||
fundingMgr *fundingManager
|
fundingMgr *fundingManager
|
||||||
@ -63,8 +64,8 @@ type server struct {
|
|||||||
|
|
||||||
// newServer creates a new instance of the server which is to listen using the
|
// newServer creates a new instance of the server which is to listen using the
|
||||||
// passed listener address.
|
// passed listener address.
|
||||||
func newServer(listenAddrs []string, wallet *lnwallet.LightningWallet,
|
func newServer(listenAddrs []string, notifier chainntnfs.ChainNotifier,
|
||||||
chanDB *channeldb.DB) (*server, error) {
|
wallet *lnwallet.LightningWallet, chanDB *channeldb.DB) (*server, error) {
|
||||||
|
|
||||||
privKey, err := getIdentityPrivKey(chanDB, wallet)
|
privKey, err := getIdentityPrivKey(chanDB, wallet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,19 +82,20 @@ func newServer(listenAddrs []string, wallet *lnwallet.LightningWallet,
|
|||||||
|
|
||||||
serializedPubKey := privKey.PubKey().SerializeCompressed()
|
serializedPubKey := privKey.PubKey().SerializeCompressed()
|
||||||
s := &server{
|
s := &server{
|
||||||
chanDB: chanDB,
|
chainNotifier: notifier,
|
||||||
fundingMgr: newFundingManager(wallet),
|
chanDB: chanDB,
|
||||||
htlcSwitch: newHtlcSwitch(),
|
fundingMgr: newFundingManager(wallet),
|
||||||
invoices: newInvoiceRegistry(),
|
htlcSwitch: newHtlcSwitch(),
|
||||||
lnwallet: wallet,
|
invoices: newInvoiceRegistry(),
|
||||||
identityPriv: privKey,
|
lnwallet: wallet,
|
||||||
lightningID: fastsha256.Sum256(serializedPubKey),
|
identityPriv: privKey,
|
||||||
listeners: listeners,
|
lightningID: fastsha256.Sum256(serializedPubKey),
|
||||||
peers: make(map[int32]*peer),
|
listeners: listeners,
|
||||||
newPeers: make(chan *peer, 100),
|
peers: make(map[int32]*peer),
|
||||||
donePeers: make(chan *peer, 100),
|
newPeers: make(chan *peer, 100),
|
||||||
queries: make(chan interface{}),
|
donePeers: make(chan *peer, 100),
|
||||||
quit: make(chan struct{}),
|
queries: make(chan interface{}),
|
||||||
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): remove
|
// TODO(roasbeef): remove
|
||||||
@ -110,10 +112,10 @@ func newServer(listenAddrs []string, wallet *lnwallet.LightningWallet,
|
|||||||
|
|
||||||
// Start starts the main daemon server, all requested listeners, and any helper
|
// Start starts the main daemon server, all requested listeners, and any helper
|
||||||
// goroutines.
|
// goroutines.
|
||||||
func (s *server) Start() {
|
func (s *server) Start() error {
|
||||||
// Already running?
|
// Already running?
|
||||||
if atomic.AddInt32(&s.started, 1) != 1 {
|
if atomic.AddInt32(&s.started, 1) != 1 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start all the listeners.
|
// Start all the listeners.
|
||||||
@ -122,12 +124,30 @@ func (s *server) Start() {
|
|||||||
go s.listener(l)
|
go s.listener(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.fundingMgr.Start()
|
// Start the notification server. This is used so channel managment
|
||||||
s.htlcSwitch.Start()
|
// goroutines can be notified when a funding transaction reaches a
|
||||||
|
// sufficient number of confirmations, or when the input for the
|
||||||
|
// funding transaction is spent in an attempt at an uncooperative
|
||||||
|
// close by the counter party.
|
||||||
|
if err := s.chainNotifier.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.rpcServer.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.fundingMgr.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.htlcSwitch.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
s.routingMgr.Start()
|
s.routingMgr.Start()
|
||||||
|
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go s.queryHandler()
|
go s.queryHandler()
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop gracefully shutsdown the main daemon server. This function will signal
|
// Stop gracefully shutsdown the main daemon server. This function will signal
|
||||||
@ -146,10 +166,14 @@ func (s *server) Stop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown the wallet, funding manager, and the rpc server.
|
||||||
|
s.chainNotifier.Stop()
|
||||||
s.rpcServer.Stop()
|
s.rpcServer.Stop()
|
||||||
s.lnwallet.Shutdown()
|
|
||||||
s.fundingMgr.Stop()
|
s.fundingMgr.Stop()
|
||||||
s.routingMgr.Stop()
|
s.routingMgr.Stop()
|
||||||
|
s.htlcSwitch.Stop()
|
||||||
|
|
||||||
|
s.lnwallet.Shutdown()
|
||||||
|
|
||||||
// Signal all the lingering goroutines to quit.
|
// Signal all the lingering goroutines to quit.
|
||||||
close(s.quit)
|
close(s.quit)
|
||||||
|
Loading…
Reference in New Issue
Block a user