From beb5d14ed99cd61e634abde12b8e4a04a8f42cd8 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 24 Aug 2018 15:30:23 +0200 Subject: [PATCH 1/5] lnwallet/btcwallet: add compile time check for BlockChainIO interface --- contractcourt/channel_arbitrator_test.go | 2 ++ lnwallet/btcwallet/btcwallet.go | 3 ++- mock.go | 2 ++ sweep/test_utils.go | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/contractcourt/channel_arbitrator_test.go b/contractcourt/channel_arbitrator_test.go index 758fd4cd..e829754f 100644 --- a/contractcourt/channel_arbitrator_test.go +++ b/contractcourt/channel_arbitrator_test.go @@ -124,6 +124,8 @@ func (b *mockArbitratorLog) WipeHistory() error { type mockChainIO struct{} +var _ lnwallet.BlockChainIO = (*mockChainIO)(nil) + func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) { return nil, 0, nil } diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go index f0cc4049..22baf110 100644 --- a/lnwallet/btcwallet/btcwallet.go +++ b/lnwallet/btcwallet/btcwallet.go @@ -67,8 +67,9 @@ type BtcWallet struct { } // A compile time check to ensure that BtcWallet implements the -// WalletController interface. +// WalletController and BlockChainIO interfaces. var _ lnwallet.WalletController = (*BtcWallet)(nil) +var _ lnwallet.BlockChainIO = (*BtcWallet)(nil) // New returns a new fully initialized instance of BtcWallet given a valid // configuration struct. diff --git a/mock.go b/mock.go index 10e077c5..00292c8b 100644 --- a/mock.go +++ b/mock.go @@ -205,6 +205,8 @@ type mockChainIO struct { bestHeight int32 } +var _ lnwallet.BlockChainIO = (*mockChainIO)(nil) + func (m *mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) { return activeNetParams.GenesisHash, m.bestHeight, nil } diff --git a/sweep/test_utils.go b/sweep/test_utils.go index bf71d602..0362741a 100644 --- a/sweep/test_utils.go +++ b/sweep/test_utils.go @@ -10,6 +10,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/lnwallet" ) var ( @@ -237,6 +238,8 @@ func (m *MockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, type mockChainIO struct{} +var _ lnwallet.BlockChainIO = (*mockChainIO)(nil) + func (m *mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) { return nil, mockChainIOHeight, nil } From 10070ecab7fce2a71425afb90a74f8e3331e9a50 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 24 Aug 2018 15:31:57 +0200 Subject: [PATCH 2/5] lnwallet: make BlockChainIO.GetUTXO take cancel chan Use quit channels as cancel chan for call to GetUTXO. --- contractcourt/channel_arbitrator_test.go | 2 +- lnwallet/btcwallet/blockchain.go | 2 +- lnwallet/interface.go | 6 ++++-- lnwallet/wallet.go | 2 +- mock.go | 2 +- routing/notifications_test.go | 3 ++- routing/router.go | 1 + sweep/test_utils.go | 2 +- 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/contractcourt/channel_arbitrator_test.go b/contractcourt/channel_arbitrator_test.go index e829754f..addf2c50 100644 --- a/contractcourt/channel_arbitrator_test.go +++ b/contractcourt/channel_arbitrator_test.go @@ -131,7 +131,7 @@ func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) { } func (*mockChainIO) GetUtxo(op *wire.OutPoint, _ []byte, - heightHint uint32) (*wire.TxOut, error) { + heightHint uint32, _ <-chan struct{}) (*wire.TxOut, error) { return nil, nil } diff --git a/lnwallet/btcwallet/blockchain.go b/lnwallet/btcwallet/blockchain.go index 62a72650..ecb5f1a2 100644 --- a/lnwallet/btcwallet/blockchain.go +++ b/lnwallet/btcwallet/blockchain.go @@ -38,7 +38,7 @@ func (b *BtcWallet) GetBestBlock() (*chainhash.Hash, int32, error) { // // This method is a part of the lnwallet.BlockChainIO interface. func (b *BtcWallet) GetUtxo(op *wire.OutPoint, pkScript []byte, - heightHint uint32) (*wire.TxOut, error) { + heightHint uint32, cancel <-chan struct{}) (*wire.TxOut, error) { switch backend := b.chain.(type) { diff --git a/lnwallet/interface.go b/lnwallet/interface.go index d3f53a0e..395da6d1 100644 --- a/lnwallet/interface.go +++ b/lnwallet/interface.go @@ -268,8 +268,10 @@ type BlockChainIO interface { // script that the outpoint creates. In the case that the output is in // the UTXO set, then the output corresponding to that output is // returned. Otherwise, a non-nil error will be returned. - GetUtxo(op *wire.OutPoint, pkScript []byte, - heightHint uint32) (*wire.TxOut, error) + // As for some backends this call can initiate a rescan, the passed + // cancel channel can be closed to abort the call. + GetUtxo(op *wire.OutPoint, pkScript []byte, heightHint uint32, + cancel <-chan struct{}) (*wire.TxOut, error) // GetBlockHash returns the hash of the block in the best blockchain // at the given height. diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index ed39a995..27da0004 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -974,7 +974,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs } output, err := l.Cfg.ChainIO.GetUtxo( &txin.PreviousOutPoint, - pkScript, 0, + pkScript, 0, l.quit, ) if output == nil { msg.err <- fmt.Errorf("input to funding tx "+ diff --git a/mock.go b/mock.go index 00292c8b..657069f4 100644 --- a/mock.go +++ b/mock.go @@ -212,7 +212,7 @@ func (m *mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) { } func (*mockChainIO) GetUtxo(op *wire.OutPoint, _ []byte, - heightHint uint32) (*wire.TxOut, error) { + heightHint uint32, _ <-chan struct{}) (*wire.TxOut, error) { return nil, nil } diff --git a/routing/notifications_test.go b/routing/notifications_test.go index 3b97a891..548ed51c 100644 --- a/routing/notifications_test.go +++ b/routing/notifications_test.go @@ -181,7 +181,8 @@ func (m *mockChain) addUtxo(op wire.OutPoint, out *wire.TxOut) { m.utxos[op] = *out m.Unlock() } -func (m *mockChain) GetUtxo(op *wire.OutPoint, _ []byte, _ uint32) (*wire.TxOut, error) { +func (m *mockChain) GetUtxo(op *wire.OutPoint, _ []byte, _ uint32, + _ <-chan struct{}) (*wire.TxOut, error) { m.RLock() defer m.RUnlock() diff --git a/routing/router.go b/routing/router.go index 96f503ab..acefcd93 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1113,6 +1113,7 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error { // been closed so we'll ignore it. chanUtxo, err := r.cfg.Chain.GetUtxo( fundingPoint, fundingPkScript, channelID.BlockHeight, + r.quit, ) if err != nil { r.rejectMtx.Lock() diff --git a/sweep/test_utils.go b/sweep/test_utils.go index 0362741a..c221449e 100644 --- a/sweep/test_utils.go +++ b/sweep/test_utils.go @@ -245,7 +245,7 @@ func (m *mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) { } func (m *mockChainIO) GetUtxo(op *wire.OutPoint, pkScript []byte, - heightHint uint32) (*wire.TxOut, error) { + heightHint uint32, _ <-chan struct{}) (*wire.TxOut, error) { return nil, nil } From 61101823710694362ed4beb58d103f9b20857206 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 24 Aug 2018 15:35:34 +0200 Subject: [PATCH 3/5] lnwallet/btcwallet: provide cancel chan as neutrino QuitChan option This will make sure a long-running rescan can be canceled in case Neutrino is the backend. --- lnwallet/btcwallet/blockchain.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lnwallet/btcwallet/blockchain.go b/lnwallet/btcwallet/blockchain.go index ecb5f1a2..8aeb3338 100644 --- a/lnwallet/btcwallet/blockchain.go +++ b/lnwallet/btcwallet/blockchain.go @@ -51,6 +51,7 @@ func (b *BtcWallet) GetUtxo(op *wire.OutPoint, pkScript []byte, neutrino.StartBlock(&waddrmgr.BlockStamp{ Height: int32(heightHint), }), + neutrino.QuitChan(cancel), ) if err != nil { return nil, err From 183adf6e612692a6426616a2a8566d6c9c0818a2 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 24 Aug 2018 15:37:04 +0200 Subject: [PATCH 4/5] chainntnfs/neutrino: provide n.quit as neutrino QuitChan option This will make sure a long-running rescan can be canceled in the case the notifier is shutting down. --- chainntnfs/neutrinonotify/neutrino.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chainntnfs/neutrinonotify/neutrino.go b/chainntnfs/neutrinonotify/neutrino.go index 76a6b71e..e23c49d0 100644 --- a/chainntnfs/neutrinonotify/neutrino.go +++ b/chainntnfs/neutrinonotify/neutrino.go @@ -764,6 +764,7 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, neutrino.EndBlock(&waddrmgr.BlockStamp{ Height: int32(historicalDispatch.EndHeight), }), + neutrino.QuitChan(n.quit), ) if err != nil && !strings.Contains(err.Error(), "not found") { return nil, err From f589c869631d2aed4a8e93da9c9b8f8648f7b5d9 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 22 Mar 2019 08:41:46 +0100 Subject: [PATCH 5/5] lnwallet/wallet: add missing error handling --- lnwallet/wallet.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 27da0004..5d2646bf 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -971,7 +971,12 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs txin.Witness[len(txin.Witness)-1], ) if err != nil { + msg.err <- fmt.Errorf("cannot create script: "+ + "%v", err) + msg.completeChan <- nil + return } + output, err := l.Cfg.ChainIO.GetUtxo( &txin.PreviousOutPoint, pkScript, 0, l.quit,