2
0
mirror of https://github.com/lightninglabs/loop synced 2024-11-09 19:10:47 +00:00
loop/test/walletkit_mock.go
Andras Banki-Horvath a55c461a8f
test: support incomplete mocks
Updating the mocks to be complete implementation of the underlying
interfaces is not always possible due to cross dependency issues.
This commit embeds the interfaces into the mocks so we can at least
always compile them.
2024-09-02 18:49:22 +02:00

273 lines
8.1 KiB
Go

package test
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/psbt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightninglabs/lndclient"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
)
// DefaultMockFee is the default value we use for fee estimates when no values
// are set for specific conf targets.
var DefaultMockFee = chainfee.SatPerKWeight(10000)
type mockWalletKit struct {
lndclient.WalletKitClient
lnd *LndMockServices
keyIndex int32
feeEstimateLock sync.Mutex
feeEstimates map[int32]chainfee.SatPerKWeight
}
var _ lndclient.WalletKitClient = (*mockWalletKit)(nil)
func (m *mockWalletKit) ListUnspent(ctx context.Context, minConfs,
maxConfs int32, opts ...lndclient.ListUnspentOption) (
[]*lnwallet.Utxo, error) {
return nil, nil
}
func (m *mockWalletKit) ListLeases(
context.Context) ([]lndclient.LeaseDescriptor, error) {
return nil, nil
}
func (m *mockWalletKit) LeaseOutput(ctx context.Context, lockID wtxmgr.LockID,
op wire.OutPoint, duration time.Duration) (time.Time, error) {
return time.Now(), nil
}
func (m *mockWalletKit) ReleaseOutput(ctx context.Context,
lockID wtxmgr.LockID, op wire.OutPoint) error {
return nil
}
func (m *mockWalletKit) DeriveNextKey(ctx context.Context, family int32) (
*keychain.KeyDescriptor, error) {
index := m.keyIndex
_, pubKey := CreateKey(index)
m.keyIndex++
return &keychain.KeyDescriptor{
KeyLocator: keychain.KeyLocator{
Family: keychain.KeyFamily(family),
Index: uint32(index),
},
PubKey: pubKey,
}, nil
}
func (m *mockWalletKit) DeriveKey(ctx context.Context, in *keychain.KeyLocator) (
*keychain.KeyDescriptor, error) {
_, pubKey := CreateKey(int32(in.Index))
return &keychain.KeyDescriptor{
KeyLocator: *in,
PubKey: pubKey,
}, nil
}
func (m *mockWalletKit) NextAddr(context.Context, string, walletrpc.AddressType,
bool) (btcutil.Address, error) {
addr, err := btcutil.NewAddressWitnessPubKeyHash(
make([]byte, 20), &chaincfg.TestNet3Params,
)
if err != nil {
return nil, err
}
return addr, nil
}
func (m *mockWalletKit) PublishTransaction(ctx context.Context, tx *wire.MsgTx,
_ string) error {
m.lnd.AddTx(tx)
m.lnd.TxPublishChannel <- tx
return nil
}
func (m *mockWalletKit) SendOutputs(ctx context.Context, outputs []*wire.TxOut,
feeRate chainfee.SatPerKWeight, _ string) (*wire.MsgTx, error) {
var inputTxHash chainhash.Hash
tx := wire.MsgTx{}
tx.AddTxIn(&wire.TxIn{
PreviousOutPoint: wire.OutPoint{
Hash: inputTxHash,
Index: 0,
},
})
for _, out := range outputs {
tx.AddTxOut(&wire.TxOut{
PkScript: out.PkScript,
Value: out.Value,
})
}
m.lnd.AddTx(&tx)
m.lnd.SendOutputsChannel <- tx
return &tx, nil
}
func (m *mockWalletKit) setFeeEstimate(confTarget int32, fee chainfee.SatPerKWeight) {
m.feeEstimateLock.Lock()
defer m.feeEstimateLock.Unlock()
m.feeEstimates[confTarget] = fee
}
func (m *mockWalletKit) EstimateFeeRate(ctx context.Context,
confTarget int32) (chainfee.SatPerKWeight, error) {
m.feeEstimateLock.Lock()
defer m.feeEstimateLock.Unlock()
if confTarget <= 1 {
return 0, errors.New("conf target must be greater than 1")
}
feeEstimate, ok := m.feeEstimates[confTarget]
if !ok {
return DefaultMockFee, nil
}
return feeEstimate, nil
}
// ListSweeps returns a list of the sweep transaction ids known to our node.
func (m *mockWalletKit) ListSweeps(_ context.Context, _ int32) (
[]string, error) {
return m.lnd.Sweeps, nil
}
// ListSweepsVerbose returns a list of sweep transactions known to our node
// with verbose information about each sweep.
func (m *mockWalletKit) ListSweepsVerbose(ctx context.Context, _ int32) (
[]lnwallet.TransactionDetail, error) {
return m.lnd.SweepsVerbose, nil
}
// BumpFee attempts to bump the fee of a transaction by spending one of
// its outputs at the given fee rate. This essentially results in a
// child-pays-for-parent (CPFP) scenario. If the given output has been
// used in a previous BumpFee call, then a transaction replacing the
// previous is broadcast, resulting in a replace-by-fee (RBF) scenario.
func (m *mockWalletKit) BumpFee(context.Context, wire.OutPoint,
chainfee.SatPerKWeight) error {
return nil
}
// ListAccounts retrieves all accounts belonging to the wallet by default.
// Optional name and addressType can be provided to filter through all of the
// wallet accounts and return only those matching.
func (m *mockWalletKit) ListAccounts(context.Context, string,
walletrpc.AddressType) ([]*walletrpc.Account, error) {
return nil, nil
}
// FundPsbt creates a fully populated PSBT that contains enough inputs
// to fund the outputs specified in the template. There are two ways of
// specifying a template: Either by passing in a PSBT with at least one
// output declared or by passing in a raw TxTemplate message. If there
// are no inputs specified in the template, coin selection is performed
// automatically. If the template does contain any inputs, it is assumed
// that full coin selection happened externally and no additional inputs
// are added. If the specified inputs aren't enough to fund the outputs
// with the given fee rate, an error is returned.
// After either selecting or verifying the inputs, all input UTXOs are
// locked with an internal app ID.
//
// NOTE: If this method returns without an error, it is the caller's
// responsibility to either spend the locked UTXOs (by finalizing and
// then publishing the transaction) or to unlock/release the locked
// UTXOs in case of an error on the caller's side.
func (m *mockWalletKit) FundPsbt(_ context.Context,
_ *walletrpc.FundPsbtRequest) (*psbt.Packet, int32,
[]*walletrpc.UtxoLease, error) {
return nil, 0, nil, nil
}
// SignPsbt expects a partial transaction with all inputs and outputs
// fully declared and tries to sign all unsigned inputs that have all
// required fields (UTXO information, BIP32 derivation information,
// witness or sig scripts) set.
// If no error is returned, the PSBT is ready to be given to the next
// signer or to be finalized if lnd was the last signer.
//
// NOTE: This RPC only signs inputs (and only those it can sign), it
// does not perform any other tasks (such as coin selection, UTXO
// locking or input/output/fee value validation, PSBT finalization). Any
// input that is incomplete will be skipped.
func (m *mockWalletKit) SignPsbt(_ context.Context,
_ *psbt.Packet) (*psbt.Packet, error) {
return nil, nil
}
// FinalizePsbt expects a partial transaction with all inputs and
// outputs fully declared and tries to sign all inputs that belong to
// the wallet. Lnd must be the last signer of the transaction. That
// means, if there are any unsigned non-witness inputs or inputs without
// UTXO information attached or inputs without witness data that do not
// belong to lnd's wallet, this method will fail. If no error is
// returned, the PSBT is ready to be extracted and the final TX within
// to be broadcast.
//
// NOTE: This method does NOT publish the transaction once finalized. It
// is the caller's responsibility to either publish the transaction on
// success or unlock/release any locked UTXOs in case of an error in
// this method.
func (m *mockWalletKit) FinalizePsbt(_ context.Context, _ *psbt.Packet,
_ string) (*psbt.Packet, *wire.MsgTx, error) {
return nil, nil, nil
}
// ImportPublicKey imports a public key as watch-only into the wallet.
func (m *mockWalletKit) ImportPublicKey(ctx context.Context,
pubkey *btcec.PublicKey, addrType lnwallet.AddressType) error {
return fmt.Errorf("unimplemented")
}
// ImportTaprootScript imports a user-provided taproot script into the
// wallet. The imported script will act as a pay-to-taproot address.
func (m *mockWalletKit) ImportTaprootScript(ctx context.Context,
tapscript *waddrmgr.Tapscript) (btcutil.Address, error) {
return nil, fmt.Errorf("unimplemented")
}