lnd/sweep/backend_mock_test.go
carla 75370ce6b4
multi: update WalletController PublishTransaction to include label
Add label parameter to PublishTransaction in WalletController
interface. A labels package is added to store generic labels that are
used for the different types of transactions that are published by lnd.

To keep commit size down, the two endpoints that require a label
parameter be passed down have a todo added, which will be removed in
subsequent commits.
2020-05-19 13:30:00 +02:00

142 lines
3.5 KiB
Go

package sweep
import (
"sync"
"testing"
"time"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnwallet"
)
// mockBackend simulates a chain backend for realistic behaviour in unit tests
// around double spends.
type mockBackend struct {
t *testing.T
lock sync.Mutex
notifier *MockNotifier
confirmedSpendInputs map[wire.OutPoint]struct{}
unconfirmedTxes map[chainhash.Hash]*wire.MsgTx
unconfirmedSpendInputs map[wire.OutPoint]struct{}
publishChan chan wire.MsgTx
walletUtxos []*lnwallet.Utxo
}
func newMockBackend(t *testing.T, notifier *MockNotifier) *mockBackend {
return &mockBackend{
t: t,
notifier: notifier,
unconfirmedTxes: make(map[chainhash.Hash]*wire.MsgTx),
confirmedSpendInputs: make(map[wire.OutPoint]struct{}),
unconfirmedSpendInputs: make(map[wire.OutPoint]struct{}),
publishChan: make(chan wire.MsgTx, 2),
}
}
func (b *mockBackend) publishTransaction(tx *wire.MsgTx) error {
b.lock.Lock()
defer b.lock.Unlock()
txHash := tx.TxHash()
if _, ok := b.unconfirmedTxes[txHash]; ok {
// Tx already exists
testLog.Tracef("mockBackend duplicate tx %v", tx.TxHash())
return lnwallet.ErrDoubleSpend
}
for _, in := range tx.TxIn {
if _, ok := b.unconfirmedSpendInputs[in.PreviousOutPoint]; ok {
// Double spend
testLog.Tracef("mockBackend double spend tx %v", tx.TxHash())
return lnwallet.ErrDoubleSpend
}
if _, ok := b.confirmedSpendInputs[in.PreviousOutPoint]; ok {
// Already included in block
testLog.Tracef("mockBackend already in block tx %v", tx.TxHash())
return lnwallet.ErrDoubleSpend
}
}
b.unconfirmedTxes[txHash] = tx
for _, in := range tx.TxIn {
b.unconfirmedSpendInputs[in.PreviousOutPoint] = struct{}{}
}
testLog.Tracef("mockBackend publish tx %v", tx.TxHash())
return nil
}
func (b *mockBackend) PublishTransaction(tx *wire.MsgTx, _ string) error {
log.Tracef("Publishing tx %v", tx.TxHash())
err := b.publishTransaction(tx)
select {
case b.publishChan <- *tx:
case <-time.After(defaultTestTimeout):
b.t.Fatalf("unexpected tx published")
}
return err
}
func (b *mockBackend) ListUnspentWitness(minconfirms, maxconfirms int32) (
[]*lnwallet.Utxo, error) {
return b.walletUtxos, nil
}
func (b *mockBackend) WithCoinSelectLock(f func() error) error {
return f()
}
func (b *mockBackend) deleteUnconfirmed(txHash chainhash.Hash) {
b.lock.Lock()
defer b.lock.Unlock()
tx, ok := b.unconfirmedTxes[txHash]
if !ok {
// Tx already exists
testLog.Errorf("mockBackend delete tx not existing %v", txHash)
return
}
testLog.Tracef("mockBackend delete tx %v", tx.TxHash())
delete(b.unconfirmedTxes, txHash)
for _, in := range tx.TxIn {
delete(b.unconfirmedSpendInputs, in.PreviousOutPoint)
}
}
func (b *mockBackend) mine() {
b.lock.Lock()
defer b.lock.Unlock()
notifications := make(map[wire.OutPoint]*wire.MsgTx)
for _, tx := range b.unconfirmedTxes {
testLog.Tracef("mockBackend mining tx %v", tx.TxHash())
for _, in := range tx.TxIn {
b.confirmedSpendInputs[in.PreviousOutPoint] = struct{}{}
notifications[in.PreviousOutPoint] = tx
}
}
b.unconfirmedSpendInputs = make(map[wire.OutPoint]struct{})
b.unconfirmedTxes = make(map[chainhash.Hash]*wire.MsgTx)
for outpoint, tx := range notifications {
testLog.Tracef("mockBackend delivering spend ntfn for %v",
outpoint)
b.notifier.SpendOutpoint(outpoint, *tx)
}
}
func (b *mockBackend) isDone() bool {
return len(b.unconfirmedTxes) == 0
}