loop/test/lnd_services_mock.go
Harsha Goli 9db43a4dbd
loop: Reimplement SelectHopHints from lnd
In this commit, instead of importing SelectHopHints from lnd, we chose
to reimplement the functionality here, for the purpose of adding hop
hints in case the user informs us the client node is considered private.

In the future, we should modify the origin SelectHopHints to take
closures for all it's data sources, so we can use it's logic external
2021-12-07 14:23:41 -05:00

263 lines
6.9 KiB
Go

package test
import (
"context"
"errors"
"sync"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/lndclient"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/zpay32"
)
var (
testStartingHeight = int32(600)
testNodePubkey = "03f5374b16f0b1f1b49101de1b9d89e0b460bc57ce9c2f9" +
"132b73dfc76d3704daa"
testSignature = []byte{55, 66, 77, 88, 99}
testSignatureMsg = "test"
)
// NewMockLnd returns a new instance of LndMockServices that can be used in unit
// tests.
func NewMockLnd() *LndMockServices {
lightningClient := &mockLightningClient{}
walletKit := &mockWalletKit{
feeEstimates: make(map[int32]chainfee.SatPerKWeight),
}
chainNotifier := &mockChainNotifier{}
signer := &mockSigner{}
invoices := &mockInvoices{}
router := &mockRouter{}
versioner := newMockVersioner()
lnd := LndMockServices{
LndServices: lndclient.LndServices{
WalletKit: walletKit,
Client: lightningClient,
ChainNotifier: chainNotifier,
Signer: signer,
Invoices: invoices,
Router: router,
ChainParams: &chaincfg.TestNet3Params,
Versioner: versioner,
},
SendPaymentChannel: make(chan PaymentChannelMessage),
ConfChannel: make(chan *chainntnfs.TxConfirmation),
RegisterConfChannel: make(chan *ConfRegistration),
RegisterSpendChannel: make(chan *SpendRegistration),
SpendChannel: make(chan *chainntnfs.SpendDetail),
TxPublishChannel: make(chan *wire.MsgTx),
SendOutputsChannel: make(chan wire.MsgTx),
SettleInvoiceChannel: make(chan lntypes.Preimage),
SingleInvoiceSubcribeChannel: make(chan *SingleInvoiceSubscription, 1),
RouterSendPaymentChannel: make(chan RouterPaymentChannelMessage),
TrackPaymentChannel: make(chan TrackPaymentMessage),
SignOutputRawChannel: make(chan SignOutputRawRequest),
FailInvoiceChannel: make(chan lntypes.Hash, 2),
epochChannel: make(chan int32),
Height: testStartingHeight,
NodePubkey: testNodePubkey,
Signature: testSignature,
SignatureMsg: testSignatureMsg,
Invoices: make(map[lntypes.Hash]*lndclient.Invoice),
}
lightningClient.lnd = &lnd
chainNotifier.lnd = &lnd
walletKit.lnd = &lnd
invoices.lnd = &lnd
router.lnd = &lnd
signer.lnd = &lnd
// Also simulate the cached info that is loaded on startup.
info, _ := lightningClient.GetInfo(context.Background())
version, _ := versioner.GetVersion(context.Background())
lnd.LndServices.NodeAlias = info.Alias
lnd.LndServices.NodePubkey = info.IdentityPubkey
lnd.LndServices.Version = version
lnd.WaitForFinished = func() {
chainNotifier.WaitForFinished()
lightningClient.WaitForFinished()
invoices.WaitForFinished()
}
return &lnd
}
// PaymentChannelMessage is the data that passed through SendPaymentChannel.
type PaymentChannelMessage struct {
PaymentRequest string
Done chan lndclient.PaymentResult
}
// TrackPaymentMessage is the data that passed through TrackPaymentChannel.
type TrackPaymentMessage struct {
Hash lntypes.Hash
Updates chan lndclient.PaymentStatus
Errors chan error
}
// RouterPaymentChannelMessage is the data that passed through RouterSendPaymentChannel.
type RouterPaymentChannelMessage struct {
lndclient.SendPaymentRequest
TrackPaymentMessage
}
// SingleInvoiceSubscription contains the single invoice subscribers
type SingleInvoiceSubscription struct {
Hash lntypes.Hash
Update chan lndclient.InvoiceUpdate
Err chan error
}
// SignOutputRawRequest contains input data for a tx signing request.
type SignOutputRawRequest struct {
Tx *wire.MsgTx
SignDescriptors []*lndclient.SignDescriptor
}
// LndMockServices provides a full set of mocked lnd services.
type LndMockServices struct {
lndclient.LndServices
SendPaymentChannel chan PaymentChannelMessage
SpendChannel chan *chainntnfs.SpendDetail
TxPublishChannel chan *wire.MsgTx
SendOutputsChannel chan wire.MsgTx
SettleInvoiceChannel chan lntypes.Preimage
FailInvoiceChannel chan lntypes.Hash
epochChannel chan int32
ConfChannel chan *chainntnfs.TxConfirmation
RegisterConfChannel chan *ConfRegistration
RegisterSpendChannel chan *SpendRegistration
SingleInvoiceSubcribeChannel chan *SingleInvoiceSubscription
RouterSendPaymentChannel chan RouterPaymentChannelMessage
TrackPaymentChannel chan TrackPaymentMessage
SignOutputRawChannel chan SignOutputRawRequest
Height int32
NodePubkey string
Signature []byte
SignatureMsg string
Transactions []lndclient.Transaction
Sweeps []string
// Invoices is a set of invoices that have been created by the mock,
// keyed by hash string.
Invoices map[lntypes.Hash]*lndclient.Invoice
Channels []lndclient.ChannelInfo
ChannelEdges map[uint64]*lndclient.ChannelEdge
ClosedChannels []lndclient.ClosedChannel
ForwardingEvents []lndclient.ForwardingEvent
Payments []lndclient.Payment
WaitForFinished func()
lock sync.Mutex
}
// NotifyHeight notifies a new block height.
func (s *LndMockServices) NotifyHeight(height int32) error {
s.Height = height
select {
case s.epochChannel <- height:
case <-time.After(Timeout):
return ErrTimeout
}
return nil
}
// AddRelevantTx marks the given transaction as relevant.
func (s *LndMockServices) AddTx(tx *wire.MsgTx) {
s.lock.Lock()
s.Transactions = append(s.Transactions, lndclient.Transaction{
Tx: tx.Copy(),
})
s.lock.Unlock()
}
// IsDone checks whether all channels have been fully emptied. If not this may
// indicate unexpected behaviour of the code under test.
func (s *LndMockServices) IsDone() error {
select {
case <-s.SendPaymentChannel:
return errors.New("SendPaymentChannel not empty")
default:
}
select {
case <-s.SpendChannel:
return errors.New("SpendChannel not empty")
default:
}
select {
case <-s.TxPublishChannel:
return errors.New("TxPublishChannel not empty")
default:
}
select {
case <-s.SendOutputsChannel:
return errors.New("SendOutputsChannel not empty")
default:
}
select {
case <-s.SettleInvoiceChannel:
return errors.New("SettleInvoiceChannel not empty")
default:
}
select {
case <-s.ConfChannel:
return errors.New("ConfChannel not empty")
default:
}
select {
case <-s.RegisterConfChannel:
return errors.New("RegisterConfChannel not empty")
default:
}
select {
case <-s.RegisterSpendChannel:
return errors.New("RegisterSpendChannel not empty")
default:
}
return nil
}
// DecodeInvoice decodes a payment request string.
func (s *LndMockServices) DecodeInvoice(request string) (*zpay32.Invoice,
error) {
return zpay32.Decode(request, s.ChainParams)
}
func (s *LndMockServices) SetFeeEstimate(confTarget int32,
feeEstimate chainfee.SatPerKWeight) {
s.WalletKit.(*mockWalletKit).setFeeEstimate(confTarget, feeEstimate)
}