2019-03-06 20:13:50 +00:00
|
|
|
package test
|
|
|
|
|
|
|
|
import (
|
2019-03-12 15:10:37 +00:00
|
|
|
"crypto/rand"
|
2019-12-09 15:33:33 +00:00
|
|
|
"encoding/hex"
|
2019-03-06 20:13:50 +00:00
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2022-03-14 12:36:02 +00:00
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
2019-12-10 00:16:41 +00:00
|
|
|
"github.com/btcsuite/btcd/wire"
|
2020-06-17 20:25:57 +00:00
|
|
|
"github.com/lightninglabs/lndclient"
|
2023-01-09 15:36:52 +00:00
|
|
|
invpkg "github.com/lightningnetwork/lnd/invoices"
|
2019-03-06 20:13:50 +00:00
|
|
|
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
|
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
2021-10-19 21:45:15 +00:00
|
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
2019-03-06 20:13:50 +00:00
|
|
|
"github.com/lightningnetwork/lnd/zpay32"
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
)
|
|
|
|
|
|
|
|
type mockLightningClient struct {
|
|
|
|
lnd *LndMockServices
|
|
|
|
wg sync.WaitGroup
|
2020-08-13 09:17:03 +00:00
|
|
|
|
|
|
|
// Embed lndclient's interface so that lndclient can be expanded
|
|
|
|
// without the need to implement unused functions on the mock.
|
|
|
|
lndclient.LightningClient
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PayInvoice pays an invoice.
|
|
|
|
func (h *mockLightningClient) PayInvoice(ctx context.Context, invoice string,
|
|
|
|
maxFee btcutil.Amount,
|
|
|
|
outgoingChannel *uint64) chan lndclient.PaymentResult {
|
|
|
|
|
|
|
|
done := make(chan lndclient.PaymentResult, 1)
|
|
|
|
|
|
|
|
h.lnd.SendPaymentChannel <- PaymentChannelMessage{
|
|
|
|
PaymentRequest: invoice,
|
2019-03-12 15:10:37 +00:00
|
|
|
Done: done,
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return done
|
|
|
|
}
|
|
|
|
|
2020-10-12 11:34:54 +00:00
|
|
|
// DecodePaymentRequest returns a non-nil payment request.
|
|
|
|
func (h *mockLightningClient) DecodePaymentRequest(_ context.Context,
|
|
|
|
_ string) (*lndclient.PaymentRequest, error) {
|
|
|
|
|
|
|
|
return &lndclient.PaymentRequest{}, nil
|
|
|
|
}
|
|
|
|
|
2019-03-06 20:13:50 +00:00
|
|
|
func (h *mockLightningClient) WaitForFinished() {
|
|
|
|
h.wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *mockLightningClient) ConfirmedWalletBalance(ctx context.Context) (
|
|
|
|
btcutil.Amount, error) {
|
|
|
|
|
|
|
|
return 1000000, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *mockLightningClient) GetInfo(ctx context.Context) (*lndclient.Info,
|
|
|
|
error) {
|
|
|
|
|
2019-12-09 15:33:33 +00:00
|
|
|
pubKeyBytes, err := hex.DecodeString(h.lnd.NodePubkey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-03-06 20:13:50 +00:00
|
|
|
var pubKey [33]byte
|
2019-12-09 15:33:33 +00:00
|
|
|
copy(pubKey[:], pubKeyBytes)
|
2019-03-06 20:13:50 +00:00
|
|
|
return &lndclient.Info{
|
|
|
|
BlockHeight: 600,
|
|
|
|
IdentityPubkey: pubKey,
|
2019-12-09 15:33:33 +00:00
|
|
|
Uris: []string{h.lnd.NodePubkey + "@127.0.0.1:9735"},
|
2019-03-06 20:13:50 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-03-12 15:10:37 +00:00
|
|
|
func (h *mockLightningClient) EstimateFeeToP2WSH(ctx context.Context,
|
|
|
|
amt btcutil.Amount, confTarget int32) (btcutil.Amount,
|
|
|
|
error) {
|
2019-03-06 20:13:50 +00:00
|
|
|
|
2019-03-12 15:10:37 +00:00
|
|
|
return 3000, nil
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *mockLightningClient) AddInvoice(ctx context.Context,
|
|
|
|
in *invoicesrpc.AddInvoiceData) (lntypes.Hash, string, error) {
|
|
|
|
|
|
|
|
h.lnd.lock.Lock()
|
|
|
|
defer h.lnd.lock.Unlock()
|
|
|
|
|
|
|
|
var hash lntypes.Hash
|
2019-03-12 15:10:37 +00:00
|
|
|
switch {
|
|
|
|
case in.Hash != nil:
|
2019-03-06 20:13:50 +00:00
|
|
|
hash = *in.Hash
|
2019-03-12 15:10:37 +00:00
|
|
|
case in.Preimage != nil:
|
2019-03-06 20:13:50 +00:00
|
|
|
hash = (*in.Preimage).Hash()
|
2019-03-12 15:10:37 +00:00
|
|
|
default:
|
|
|
|
if _, err := rand.Read(hash[:]); err != nil {
|
|
|
|
return lntypes.Hash{}, "", err
|
|
|
|
}
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create and encode the payment request as a bech32 (zpay32) string.
|
|
|
|
creationDate := time.Now()
|
|
|
|
|
|
|
|
payReq, err := zpay32.NewInvoice(
|
|
|
|
h.lnd.ChainParams, hash, creationDate,
|
|
|
|
zpay32.Description(in.Memo),
|
|
|
|
zpay32.CLTVExpiry(in.CltvExpiry),
|
2019-12-03 09:42:01 +00:00
|
|
|
zpay32.Amount(in.Value),
|
2019-03-06 20:13:50 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return lntypes.Hash{}, "", err
|
|
|
|
}
|
|
|
|
|
2022-03-14 12:36:02 +00:00
|
|
|
privKey, err := btcec.NewPrivateKey()
|
2019-03-06 20:13:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return lntypes.Hash{}, "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
payReqString, err := payReq.Encode(
|
|
|
|
zpay32.MessageSigner{
|
|
|
|
SignCompact: func(hash []byte) ([]byte, error) {
|
2022-03-14 12:36:02 +00:00
|
|
|
// ecdsa.SignCompact returns a
|
|
|
|
// pubkey-recoverable signature.
|
|
|
|
sig, err := ecdsa.SignCompact(
|
|
|
|
privKey, hash, true,
|
2019-03-06 20:13:50 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
2022-03-14 12:36:02 +00:00
|
|
|
return nil, fmt.Errorf("can't sign "+
|
|
|
|
"the hash: %v", err)
|
2019-03-06 20:13:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sig, nil
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return lntypes.Hash{}, "", err
|
|
|
|
}
|
|
|
|
|
2020-05-20 11:42:20 +00:00
|
|
|
// Add the invoice we have created to our mock's set of invoices.
|
|
|
|
h.lnd.Invoices[hash] = &lndclient.Invoice{
|
|
|
|
Preimage: nil,
|
|
|
|
Hash: hash,
|
|
|
|
PaymentRequest: payReqString,
|
|
|
|
Amount: in.Value,
|
|
|
|
CreationDate: creationDate,
|
2023-01-09 15:36:52 +00:00
|
|
|
State: invpkg.ContractOpen,
|
2020-05-20 11:42:20 +00:00
|
|
|
IsKeysend: false,
|
|
|
|
}
|
|
|
|
|
2019-03-06 20:13:50 +00:00
|
|
|
return hash, payReqString, nil
|
|
|
|
}
|
2019-12-10 00:16:41 +00:00
|
|
|
|
2020-05-20 11:42:20 +00:00
|
|
|
// LookupInvoice looks up an invoice in the mock's set of stored invoices.
|
|
|
|
// If it is not found, this call will fail. Note that these invoices should
|
|
|
|
// be settled using settleInvoice to have a preimage, settled state and settled
|
|
|
|
// date set.
|
|
|
|
func (h *mockLightningClient) LookupInvoice(_ context.Context,
|
|
|
|
hash lntypes.Hash) (*lndclient.Invoice, error) {
|
|
|
|
|
|
|
|
h.lnd.lock.Lock()
|
|
|
|
defer h.lnd.lock.Unlock()
|
|
|
|
|
|
|
|
inv, ok := h.lnd.Invoices[hash]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("invoice: %x not found", hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
return inv, nil
|
|
|
|
}
|
|
|
|
|
2019-12-10 00:16:41 +00:00
|
|
|
// ListTransactions returns all known transactions of the backing lnd node.
|
|
|
|
func (h *mockLightningClient) ListTransactions(
|
2023-01-09 15:36:52 +00:00
|
|
|
_ context.Context, _, _ int32, _ ...lndclient.ListTransactionsOption) (
|
|
|
|
[]lndclient.Transaction, error) {
|
2019-12-10 00:16:41 +00:00
|
|
|
|
|
|
|
h.lnd.lock.Lock()
|
|
|
|
txs := h.lnd.Transactions
|
|
|
|
h.lnd.lock.Unlock()
|
2020-06-17 06:44:44 +00:00
|
|
|
|
2019-12-10 00:16:41 +00:00
|
|
|
return txs, nil
|
|
|
|
}
|
2020-01-31 20:41:18 +00:00
|
|
|
|
2021-10-19 21:45:15 +00:00
|
|
|
// GetNodeInfo retrieves info on the node, and if includeChannels is True,
|
2022-05-20 06:57:06 +00:00
|
|
|
// will return other channels the node may have with other peers.
|
2021-10-19 21:45:15 +00:00
|
|
|
func (h *mockLightningClient) GetNodeInfo(ctx context.Context,
|
|
|
|
pubKeyBytes route.Vertex, includeChannels bool) (*lndclient.NodeInfo, error) {
|
|
|
|
|
2021-12-22 18:11:50 +00:00
|
|
|
nodeInfo := &lndclient.NodeInfo{
|
|
|
|
Node: &lndclient.Node{
|
|
|
|
PubKey: pubKeyBytes,
|
|
|
|
},
|
|
|
|
}
|
2021-10-19 21:45:15 +00:00
|
|
|
|
|
|
|
if !includeChannels {
|
2021-12-22 18:11:50 +00:00
|
|
|
return nodeInfo, nil
|
2021-10-19 21:45:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nodePubKey, err := route.NewVertexFromStr(h.lnd.NodePubkey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodeInfo.Channels should only contain channels which: do not belong
|
|
|
|
// to the queried node; are not private; have the provided vertex as a
|
|
|
|
// participant
|
|
|
|
for _, edge := range h.lnd.ChannelEdges {
|
|
|
|
if (edge.Node1 == pubKeyBytes || edge.Node2 == pubKeyBytes) &&
|
|
|
|
(edge.Node1 != nodePubKey || edge.Node2 != nodePubKey) {
|
|
|
|
|
|
|
|
for _, channel := range h.lnd.Channels {
|
|
|
|
if channel.ChannelID == edge.ChannelID && !channel.Private {
|
|
|
|
nodeInfo.Channels = append(nodeInfo.Channels, *edge)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeInfo.ChannelCount = len(nodeInfo.Channels)
|
|
|
|
|
2021-12-22 18:11:50 +00:00
|
|
|
return nodeInfo, nil
|
2021-10-19 21:45:15 +00:00
|
|
|
}
|
|
|
|
|
2022-05-20 06:57:06 +00:00
|
|
|
// GetChanInfo retrieves all the info the node has on the given channel.
|
2021-10-19 21:45:15 +00:00
|
|
|
func (h *mockLightningClient) GetChanInfo(ctx context.Context,
|
|
|
|
channelID uint64) (*lndclient.ChannelEdge, error) {
|
|
|
|
|
|
|
|
var channelEdge *lndclient.ChannelEdge
|
|
|
|
if channelEdge, ok := h.lnd.ChannelEdges[channelID]; ok {
|
|
|
|
return channelEdge, nil
|
|
|
|
}
|
|
|
|
return channelEdge, fmt.Errorf("not found")
|
|
|
|
}
|
|
|
|
|
2020-05-18 14:23:02 +00:00
|
|
|
// ListChannels retrieves all channels of the backing lnd node.
|
2021-10-24 08:08:23 +00:00
|
|
|
func (h *mockLightningClient) ListChannels(ctx context.Context, _, _ bool) (
|
2020-05-18 14:23:02 +00:00
|
|
|
[]lndclient.ChannelInfo, error) {
|
|
|
|
|
|
|
|
return h.lnd.Channels, nil
|
|
|
|
}
|
|
|
|
|
2020-06-17 06:44:43 +00:00
|
|
|
// ClosedChannels returns a list of our closed channels.
|
|
|
|
func (h *mockLightningClient) ClosedChannels(_ context.Context) ([]lndclient.ClosedChannel,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return h.lnd.ClosedChannels, nil
|
|
|
|
}
|
|
|
|
|
2020-06-17 06:44:43 +00:00
|
|
|
// ForwardingHistory returns the mock's set of forwarding events.
|
|
|
|
func (h *mockLightningClient) ForwardingHistory(_ context.Context,
|
|
|
|
_ lndclient.ForwardingHistoryRequest) (*lndclient.ForwardingHistoryResponse,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return &lndclient.ForwardingHistoryResponse{
|
|
|
|
LastIndexOffset: 0,
|
|
|
|
Events: h.lnd.ForwardingEvents,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-06-17 06:44:43 +00:00
|
|
|
// ListInvoices returns our mock's invoices.
|
|
|
|
func (h *mockLightningClient) ListInvoices(_ context.Context,
|
|
|
|
_ lndclient.ListInvoicesRequest) (*lndclient.ListInvoicesResponse,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
invoices := make([]lndclient.Invoice, 0, len(h.lnd.Invoices))
|
|
|
|
for _, invoice := range h.lnd.Invoices {
|
|
|
|
invoices = append(invoices, *invoice)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &lndclient.ListInvoicesResponse{
|
|
|
|
Invoices: invoices,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-06-17 06:44:43 +00:00
|
|
|
// ListPayments makes a paginated call to our list payments endpoint.
|
|
|
|
func (h *mockLightningClient) ListPayments(_ context.Context,
|
|
|
|
_ lndclient.ListPaymentsRequest) (*lndclient.ListPaymentsResponse,
|
|
|
|
error) {
|
|
|
|
|
|
|
|
return &lndclient.ListPaymentsResponse{
|
|
|
|
Payments: h.lnd.Payments,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-01-31 20:41:18 +00:00
|
|
|
// ChannelBackup retrieves the backup for a particular channel. The
|
|
|
|
// backup is returned as an encrypted chanbackup.Single payload.
|
|
|
|
func (h *mockLightningClient) ChannelBackup(context.Context, wire.OutPoint) ([]byte, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChannelBackups retrieves backups for all existing pending open and
|
|
|
|
// open channels. The backups are returned as an encrypted
|
|
|
|
// chanbackup.Multi payload.
|
|
|
|
func (h *mockLightningClient) ChannelBackups(ctx context.Context) ([]byte, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|