75370ce6b4
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.
142 lines
3.5 KiB
Go
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
|
|
}
|