mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
The cost cleanup migration pages through LND payments only to build a payment-hash to fee map. It does not inspect HTLC attempts, routes, or per-hop data; pagination still uses the top-level index offsets returned by ListPayments. Setting OmitHops is safe for this migration because LND only strips hop-level route data from HTLC attempts, while preserving the top-level payment fields the migration reads: hash, fee, and response offsets. This reduces response size and query cost for nodes with many or large MPP payments without changing the calculated swap costs. The migration test records the mocked ListPayments requests and asserts that OmitHops is set.
299 lines
8 KiB
Go
299 lines
8 KiB
Go
package test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
|
|
"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"
|
|
"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),
|
|
minRelayFee: chainfee.FeePerKwFloor,
|
|
}
|
|
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,
|
|
},
|
|
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),
|
|
blockHeightListeners: make([]chan int32, 0),
|
|
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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// PublishHandler is optional transaction handler function called upon calling
|
|
// the method PublishTransaction.
|
|
type PublishHandler func(ctx context.Context, tx *wire.MsgTx,
|
|
label string) error
|
|
|
|
// LndMockServices provides a full set of mocked lnd services.
|
|
type LndMockServices struct {
|
|
lndclient.LndServices
|
|
|
|
SpendChannel chan *chainntnfs.SpendDetail
|
|
TxPublishChannel chan *wire.MsgTx
|
|
SendOutputsChannel chan wire.MsgTx
|
|
SettleInvoiceChannel chan lntypes.Preimage
|
|
FailInvoiceChannel chan lntypes.Hash
|
|
blockHeightListeners []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
|
|
SweepsVerbose []lnwallet.TransactionDetail
|
|
|
|
// 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
|
|
ListPaymentsRequests []lndclient.ListPaymentsRequest
|
|
MissionControlState []lndclient.MissionControlEntry
|
|
|
|
WaitForFinished func()
|
|
|
|
PublishHandler PublishHandler
|
|
|
|
lock sync.Mutex
|
|
}
|
|
|
|
// EpochSubscribers returns the number of subscribers to block epoch
|
|
// notifications.
|
|
func (s *LndMockServices) EpochSubscribers() int32 {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
return int32(len(s.blockHeightListeners))
|
|
}
|
|
|
|
// ListPaymentsRequestsSnapshot returns a copy of all ListPayments requests
|
|
// recorded by the mock.
|
|
func (s *LndMockServices) ListPaymentsRequestsSnapshot() []lndclient.ListPaymentsRequest {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
requests := make(
|
|
[]lndclient.ListPaymentsRequest, len(s.ListPaymentsRequests),
|
|
)
|
|
copy(requests, s.ListPaymentsRequests)
|
|
|
|
return requests
|
|
}
|
|
|
|
// NotifyHeight notifies a new block height.
|
|
func (s *LndMockServices) NotifyHeight(height int32) error {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
s.Height = height
|
|
|
|
for _, listener := range s.blockHeightListeners {
|
|
lis := listener
|
|
go func() {
|
|
lis <- height
|
|
}()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddTx 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.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.LndServices.WalletKit.(*mockWalletKit).setFeeEstimate(
|
|
confTarget, feeEstimate,
|
|
)
|
|
}
|
|
|
|
func (s *LndMockServices) SetMinRelayFee(feeEstimate chainfee.SatPerKWeight) {
|
|
s.LndServices.WalletKit.(*mockWalletKit).setMinRelayFee(feeEstimate)
|
|
}
|
|
|
|
// SetListUnspent sets the list of UTXOs returned by the mock's WalletKit
|
|
// ListUnspent call.
|
|
func (s *LndMockServices) SetListUnspent(utxos []*lnwallet.Utxo) {
|
|
s.LndServices.WalletKit.(*mockWalletKit).setListUnspent(utxos)
|
|
}
|