mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-20 13:27:50 +02:00
staticaddr: expose tracked deposit availability
Build list and summary responses from tracked deposit records instead of raw wallet UTXOs so RPC clients see the manager availability state. Split unconfirmed value from confirmed deposited value in summaries. Keep withdrawal and channel-open flows on confirmed inputs by rejecting unconfirmed selected deposits in those paths.
This commit is contained in:
parent
32b3b9650f
commit
ad8e2ea6ca
7 changed files with 457 additions and 99 deletions
|
|
@ -977,15 +977,22 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
|
|||
return nil, fmt.Errorf("expected %d deposits, got %d",
|
||||
len(req.DepositOutpoints),
|
||||
len(depositList.FilteredDeposits))
|
||||
} else {
|
||||
numDeposits = len(depositList.FilteredDeposits)
|
||||
}
|
||||
numDeposits = len(depositList.FilteredDeposits)
|
||||
|
||||
// In case we quote for deposits, we send the server both the
|
||||
// selected value and the number of deposits. This is so the
|
||||
// server can probe the selected value and calculate the per
|
||||
// input fee.
|
||||
for _, deposit := range depositList.FilteredDeposits {
|
||||
// For a manual quote we require the current state to be
|
||||
// Deposited so a stale client-side outpoint selection
|
||||
// fails early instead of making it to swap initiation.
|
||||
if deposit.State != looprpc.DepositState_DEPOSITED {
|
||||
return nil, fmt.Errorf("deposit %s is not "+
|
||||
"currently available", deposit.Outpoint)
|
||||
}
|
||||
|
||||
totalDepositAmount += btcutil.Amount(
|
||||
deposit.Value,
|
||||
)
|
||||
|
|
@ -1693,58 +1700,35 @@ func (s *swapClientServer) ListUnspentDeposits(ctx context.Context,
|
|||
}
|
||||
|
||||
// ListUnspentRaw returns the unspent wallet view of the backing lnd
|
||||
// wallet. It might be that deposits show up there that are actually
|
||||
// not spendable because they already have been used but not yet spent
|
||||
// by the server. We filter out such deposits here.
|
||||
// wallet. Static loop-in initiation requires an active deposit record,
|
||||
// so only deposits that are both wallet-visible and tracked as
|
||||
// Deposited are returned here.
|
||||
var (
|
||||
outpoints []string
|
||||
isUnspent = make(map[wire.OutPoint]struct{})
|
||||
)
|
||||
|
||||
// Keep track of confirmed outpoints that we need to check against our
|
||||
// database.
|
||||
confirmedToCheck := make(map[wire.OutPoint]struct{})
|
||||
|
||||
for _, utxo := range utxos {
|
||||
if utxo.Confirmations < deposit.MinConfs {
|
||||
// Unconfirmed deposits are always available.
|
||||
isUnspent[utxo.OutPoint] = struct{}{}
|
||||
} else {
|
||||
// Confirmed deposits need to be checked.
|
||||
outpoints = append(outpoints, utxo.OutPoint.String())
|
||||
confirmedToCheck[utxo.OutPoint] = struct{}{}
|
||||
}
|
||||
outpoints = append(outpoints, utxo.OutPoint.String())
|
||||
}
|
||||
|
||||
// Check the spent status of the deposits by looking at their states.
|
||||
ignoreUnknownOutpoints := false
|
||||
ignoreUnknownOutpoints := true
|
||||
deposits, err := s.depositManager.DepositsForOutpoints(
|
||||
ctx, outpoints, ignoreUnknownOutpoints,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, d := range deposits {
|
||||
// A nil deposit means we don't have a record for it. We'll
|
||||
// handle this case after the loop.
|
||||
if d == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the deposit is in the "Deposited" state, it's available.
|
||||
if d.IsInState(deposit.Deposited) {
|
||||
isUnspent[d.OutPoint] = struct{}{}
|
||||
}
|
||||
|
||||
// We have a record for this deposit, so we no longer need to
|
||||
// check it.
|
||||
delete(confirmedToCheck, d.OutPoint)
|
||||
}
|
||||
|
||||
// Any remaining outpoints in confirmedToCheck are ones that lnd knows
|
||||
// about but we don't. These are new, unspent deposits.
|
||||
for op := range confirmedToCheck {
|
||||
isUnspent[op] = struct{}{}
|
||||
}
|
||||
|
||||
// Prepare the list of unspent deposits for the rpc response.
|
||||
|
|
@ -1791,8 +1775,9 @@ func (s *swapClientServer) WithdrawDeposits(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
for _, d := range deposits {
|
||||
outpoints = append(outpoints, d.OutPoint)
|
||||
outpoints, err = withdrawAllDepositOutpoints(deposits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case isUtxoSelected:
|
||||
|
|
@ -1815,6 +1800,25 @@ func (s *swapClientServer) WithdrawDeposits(ctx context.Context,
|
|||
}, err
|
||||
}
|
||||
|
||||
// withdrawAllDepositOutpoints returns all deposit outpoints for an `all`
|
||||
// withdrawal request. The request must fail if any deposited output is still
|
||||
// unconfirmed because `all` should not silently downgrade to a subset.
|
||||
func withdrawAllDepositOutpoints(deposits []*deposit.Deposit) ([]wire.OutPoint,
|
||||
error) {
|
||||
|
||||
outpoints := make([]wire.OutPoint, 0, len(deposits))
|
||||
for _, d := range deposits {
|
||||
if d.ConfirmationHeight <= 0 {
|
||||
return nil, fmt.Errorf("can't withdraw all deposits while " +
|
||||
"some deposits are unconfirmed")
|
||||
}
|
||||
|
||||
outpoints = append(outpoints, d.OutPoint)
|
||||
}
|
||||
|
||||
return outpoints, nil
|
||||
}
|
||||
|
||||
// ListStaticAddressDeposits returns a list of all sufficiently confirmed
|
||||
// deposits behind the static address and displays properties like value,
|
||||
// state or blocks til expiry.
|
||||
|
|
@ -1987,9 +1991,10 @@ func (s *swapClientServer) ListStaticAddressSwaps(ctx context.Context,
|
|||
protoDeposits = make([]*looprpc.Deposit, 0, len(ds))
|
||||
for _, d := range ds {
|
||||
state := toClientDepositState(d.GetState())
|
||||
blocksUntilExpiry := d.ConfirmationHeight +
|
||||
int64(addrParams.Expiry) -
|
||||
int64(lndInfo.BlockHeight)
|
||||
blocksUntilExpiry := depositBlocksUntilExpiry(
|
||||
d.ConfirmationHeight, addrParams.Expiry,
|
||||
int64(lndInfo.BlockHeight),
|
||||
)
|
||||
|
||||
pd := &looprpc.Deposit{
|
||||
Id: d.ID[:],
|
||||
|
|
@ -2081,23 +2086,16 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context,
|
|||
htlcTimeoutSwept int64
|
||||
)
|
||||
|
||||
// Value unconfirmed.
|
||||
utxos, err := s.staticAddressManager.ListUnspent(
|
||||
ctx, 0, deposit.MinConfs-1,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, u := range utxos {
|
||||
valueUnconfirmed += int64(u.Value)
|
||||
}
|
||||
|
||||
// Confirmed total values by category.
|
||||
// Total values by category.
|
||||
for _, d := range allDeposits {
|
||||
value := int64(d.Value)
|
||||
switch d.GetState() {
|
||||
case deposit.Deposited:
|
||||
valueDeposited += value
|
||||
if d.ConfirmationHeight <= 0 {
|
||||
valueUnconfirmed += value
|
||||
} else {
|
||||
valueDeposited += value
|
||||
}
|
||||
|
||||
case deposit.Expired:
|
||||
valueExpired += value
|
||||
|
|
@ -2247,13 +2245,27 @@ func (s *swapClientServer) populateBlocksUntilExpiry(ctx context.Context,
|
|||
return err
|
||||
}
|
||||
for i := range len(deposits) {
|
||||
deposits[i].BlocksUntilExpiry =
|
||||
deposits[i].ConfirmationHeight +
|
||||
int64(params.Expiry) - bestBlockHeight
|
||||
deposits[i].BlocksUntilExpiry = depositBlocksUntilExpiry(
|
||||
deposits[i].ConfirmationHeight, params.Expiry,
|
||||
bestBlockHeight,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// depositBlocksUntilExpiry returns the remaining blocks until a deposit
|
||||
// expires. Unconfirmed deposits return the full CSV value because the timeout
|
||||
// has not started yet.
|
||||
func depositBlocksUntilExpiry(confirmationHeight int64, expiry uint32,
|
||||
bestBlockHeight int64) int64 {
|
||||
|
||||
if confirmationHeight <= 0 {
|
||||
return int64(expiry)
|
||||
}
|
||||
|
||||
return confirmationHeight + int64(expiry) - bestBlockHeight
|
||||
}
|
||||
|
||||
// StaticOpenChannel initiates an open channel request using static address
|
||||
// deposits.
|
||||
func (s *swapClientServer) StaticOpenChannel(ctx context.Context,
|
||||
|
|
|
|||
86
loopd/swapclient_server_deposit_test.go
Normal file
86
loopd/swapclient_server_deposit_test.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package loopd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/loop/staticaddr/deposit"
|
||||
)
|
||||
|
||||
// TestDepositBlocksUntilExpiry checks blocks-until-expiry handling for
|
||||
// confirmed and unconfirmed deposits.
|
||||
func TestDepositBlocksUntilExpiry(t *testing.T) {
|
||||
t.Run("unconfirmed", func(t *testing.T) {
|
||||
if blocks := depositBlocksUntilExpiry(0, 144, 500); blocks != 144 {
|
||||
t.Fatalf("expected 144 blocks for unconfirmed deposit, got %d",
|
||||
blocks)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("confirmed", func(t *testing.T) {
|
||||
if blocks := depositBlocksUntilExpiry(450, 144, 500); blocks != 94 {
|
||||
t.Fatalf("expected 94 blocks until expiry, got %d",
|
||||
blocks)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestWithdrawAllDepositOutpoints checks `all` withdrawal handling for
|
||||
// confirmed and unconfirmed deposits.
|
||||
func TestWithdrawAllDepositOutpoints(t *testing.T) {
|
||||
t.Run("rejects unconfirmed", func(t *testing.T) {
|
||||
deposits := []*deposit.Deposit{
|
||||
{
|
||||
OutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash{1},
|
||||
Index: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
OutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash{2},
|
||||
Index: 2,
|
||||
},
|
||||
ConfirmationHeight: 123,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := withdrawAllDepositOutpoints(deposits)
|
||||
if err == nil {
|
||||
t.Fatal("expected unconfirmed deposit to fail all withdrawal")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns all confirmed", func(t *testing.T) {
|
||||
first := wire.OutPoint{
|
||||
Hash: chainhash.Hash{3},
|
||||
Index: 3,
|
||||
}
|
||||
second := wire.OutPoint{
|
||||
Hash: chainhash.Hash{4},
|
||||
Index: 4,
|
||||
}
|
||||
deposits := []*deposit.Deposit{
|
||||
{
|
||||
OutPoint: first,
|
||||
ConfirmationHeight: 123,
|
||||
},
|
||||
{
|
||||
OutPoint: second,
|
||||
ConfirmationHeight: 124,
|
||||
},
|
||||
}
|
||||
|
||||
outpoints, err := withdrawAllDepositOutpoints(deposits)
|
||||
if err != nil {
|
||||
t.Fatalf("expected confirmed deposits to succeed: %v", err)
|
||||
}
|
||||
if len(outpoints) != 2 {
|
||||
t.Fatalf("expected 2 outpoints, got %d", len(outpoints))
|
||||
}
|
||||
if outpoints[0] != first || outpoints[1] != second {
|
||||
t.Fatal("expected all confirmed outpoints to remain selected")
|
||||
}
|
||||
})
|
||||
}
|
||||
135
loopd/swapclient_server_staticaddr_test.go
Normal file
135
loopd/swapclient_server_staticaddr_test.go
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package loopd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btclog/v2"
|
||||
"github.com/lightninglabs/loop/looprpc"
|
||||
"github.com/lightninglabs/loop/staticaddr/address"
|
||||
"github.com/lightninglabs/loop/staticaddr/deposit"
|
||||
"github.com/lightninglabs/loop/staticaddr/script"
|
||||
mock_lnd "github.com/lightninglabs/loop/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type staticAddrDepositStore struct {
|
||||
allDeposits []*deposit.Deposit
|
||||
byOutpoint map[string]*deposit.Deposit
|
||||
}
|
||||
|
||||
// CreateDeposit implements deposit.Store for static address server tests.
|
||||
func (s *staticAddrDepositStore) CreateDeposit(context.Context,
|
||||
*deposit.Deposit) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDeposit implements deposit.Store for static address server tests.
|
||||
func (s *staticAddrDepositStore) UpdateDeposit(context.Context,
|
||||
*deposit.Deposit) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDeposit implements deposit.Store for static address server tests.
|
||||
func (s *staticAddrDepositStore) GetDeposit(context.Context,
|
||||
deposit.ID) (*deposit.Deposit, error) {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DepositForOutpoint returns the deposit for the requested outpoint.
|
||||
func (s *staticAddrDepositStore) DepositForOutpoint(_ context.Context,
|
||||
outpoint string) (*deposit.Deposit, error) {
|
||||
|
||||
if deposit, ok := s.byOutpoint[outpoint]; ok {
|
||||
return deposit, nil
|
||||
}
|
||||
|
||||
return nil, deposit.ErrDepositNotFound
|
||||
}
|
||||
|
||||
// AllDeposits returns all deposits seeded into the test store.
|
||||
func (s *staticAddrDepositStore) AllDeposits(context.Context) (
|
||||
[]*deposit.Deposit, error) {
|
||||
|
||||
return s.allDeposits, nil
|
||||
}
|
||||
|
||||
// newTestDepositManager creates a deposit manager backed by seeded deposits.
|
||||
func newTestDepositManager(
|
||||
deposits ...*deposit.Deposit) *deposit.Manager {
|
||||
|
||||
byOutpoint := make(map[string]*deposit.Deposit, len(deposits))
|
||||
for _, deposit := range deposits {
|
||||
byOutpoint[deposit.OutPoint.String()] = deposit
|
||||
}
|
||||
|
||||
return deposit.NewManager(&deposit.ManagerConfig{
|
||||
Store: &staticAddrDepositStore{
|
||||
allDeposits: deposits,
|
||||
byOutpoint: byOutpoint,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// newTestStaticAddressContext creates static address test dependencies.
|
||||
func newTestStaticAddressContext(t *testing.T) (*address.Manager,
|
||||
*mock_lnd.LndMockServices) {
|
||||
|
||||
t.Helper()
|
||||
|
||||
mock := mock_lnd.NewMockLnd()
|
||||
_, client := mock_lnd.CreateKey(1)
|
||||
_, server := mock_lnd.CreateKey(2)
|
||||
|
||||
addrStore := &mockAddressStore{
|
||||
params: []*script.Parameters{{
|
||||
ClientPubkey: client,
|
||||
ServerPubkey: server,
|
||||
Expiry: 10,
|
||||
PkScript: []byte("pkscript"),
|
||||
}},
|
||||
}
|
||||
|
||||
addrMgr, err := address.NewManager(&address.ManagerConfig{
|
||||
Store: addrStore,
|
||||
WalletKit: mock.WalletKit,
|
||||
ChainParams: mock.ChainParams,
|
||||
}, 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return addrMgr, mock
|
||||
}
|
||||
|
||||
// TestGetLoopInQuoteRejectsUnavailableSelectedDeposit verifies manual quote
|
||||
// requests fail for selected deposits that are no longer available.
|
||||
func TestGetLoopInQuoteRejectsUnavailableSelectedDeposit(t *testing.T) {
|
||||
t.Parallel()
|
||||
setLogger(btclog.Disabled)
|
||||
|
||||
locked := &deposit.Deposit{
|
||||
OutPoint: wire.OutPoint{
|
||||
Hash: chainhash.Hash{6},
|
||||
Index: 6,
|
||||
},
|
||||
Value: btcutil.Amount(5_000),
|
||||
}
|
||||
locked.SetState(deposit.LoopingIn)
|
||||
|
||||
addrMgr, lnd := newTestStaticAddressContext(t)
|
||||
server := &swapClientServer{
|
||||
depositManager: newTestDepositManager(locked),
|
||||
staticAddressManager: addrMgr,
|
||||
lnd: &lnd.LndServices,
|
||||
}
|
||||
|
||||
_, err := server.GetLoopInQuote(context.Background(), &looprpc.QuoteRequest{
|
||||
DepositOutpoints: []string{locked.OutPoint.String()},
|
||||
})
|
||||
require.ErrorContains(t, err, "is not currently available")
|
||||
}
|
||||
|
|
@ -1321,7 +1321,7 @@ func (s *mockDepositStore) DepositForOutpoint(_ context.Context,
|
|||
if d, ok := s.byOutpoint[outpoint]; ok {
|
||||
return d, nil
|
||||
}
|
||||
return nil, nil
|
||||
return nil, deposit.ErrDepositNotFound
|
||||
}
|
||||
|
||||
func (s *mockDepositStore) AllDeposits(_ context.Context) ([]*deposit.Deposit,
|
||||
|
|
@ -1376,11 +1376,11 @@ func TestListUnspentDeposits(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
minConfs := int64(deposit.MinConfs)
|
||||
utxoBelow := makeUtxo(0, minConfs-1) // always included
|
||||
utxoAt := makeUtxo(1, minConfs) // included only if Deposited
|
||||
utxoAbove1 := makeUtxo(2, minConfs+1)
|
||||
utxoAbove2 := makeUtxo(3, minConfs+2)
|
||||
utxoUnknown := makeUtxo(0, 0)
|
||||
utxoDeposited := makeUtxo(1, 1)
|
||||
utxoWithdrawn := makeUtxo(2, 2)
|
||||
utxoLoopingIn := makeUtxo(3, 5)
|
||||
utxoConfirmedUnknown := makeUtxo(4, 3)
|
||||
|
||||
// Helper to build the deposit manager with specific states.
|
||||
buildDepositMgr := func(
|
||||
|
|
@ -1398,17 +1398,19 @@ func TestListUnspentDeposits(t *testing.T) {
|
|||
return deposit.NewManager(&deposit.ManagerConfig{Store: store})
|
||||
}
|
||||
|
||||
// Include below-min-conf and >=min with Deposited; exclude others.
|
||||
t.Run("below min conf always, Deposited included, others excluded",
|
||||
// Only known Deposited records are available. Unknown deposits and
|
||||
// known non-Deposited states are excluded.
|
||||
t.Run("only known Deposited included",
|
||||
func(t *testing.T) {
|
||||
mock.SetListUnspent([]*lnwallet.Utxo{
|
||||
utxoBelow, utxoAt, utxoAbove1, utxoAbove2,
|
||||
utxoUnknown, utxoDeposited, utxoWithdrawn,
|
||||
utxoLoopingIn,
|
||||
})
|
||||
|
||||
depMgr := buildDepositMgr(map[wire.OutPoint]fsm.StateType{
|
||||
utxoAt.OutPoint: deposit.Deposited,
|
||||
utxoAbove1.OutPoint: deposit.Withdrawn,
|
||||
utxoAbove2.OutPoint: deposit.LoopingIn,
|
||||
utxoDeposited.OutPoint: deposit.Deposited,
|
||||
utxoWithdrawn.OutPoint: deposit.Withdrawn,
|
||||
utxoLoopingIn.OutPoint: deposit.LoopingIn,
|
||||
})
|
||||
|
||||
server := &swapClientServer{
|
||||
|
|
@ -1421,8 +1423,8 @@ func TestListUnspentDeposits(t *testing.T) {
|
|||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect utxoBelow and utxoAt only.
|
||||
require.Len(t, resp.Utxos, 2)
|
||||
// Expect the Deposited utxo only.
|
||||
require.Len(t, resp.Utxos, 1)
|
||||
got := map[string]struct{}{}
|
||||
for _, u := range resp.Utxos {
|
||||
got[u.Outpoint] = struct{}{}
|
||||
|
|
@ -1430,25 +1432,23 @@ func TestListUnspentDeposits(t *testing.T) {
|
|||
// same across utxos.
|
||||
require.NotEmpty(t, u.StaticAddress)
|
||||
}
|
||||
_, ok1 := got[utxoBelow.OutPoint.String()]
|
||||
_, ok2 := got[utxoAt.OutPoint.String()]
|
||||
require.True(t, ok1)
|
||||
require.True(t, ok2)
|
||||
_, ok := got[utxoDeposited.OutPoint.String()]
|
||||
require.True(t, ok)
|
||||
})
|
||||
|
||||
// Swap states, now include utxoBelow and utxoAbove1.
|
||||
t.Run("Deposited on >=min included; non-Deposited excluded",
|
||||
// Confirmation depth no longer changes availability; state does.
|
||||
t.Run("availability ignores conf depth once deposit state is known",
|
||||
func(t *testing.T) {
|
||||
mock.SetListUnspent(
|
||||
[]*lnwallet.Utxo{
|
||||
utxoBelow, utxoAt, utxoAbove1,
|
||||
utxoAbove2,
|
||||
utxoUnknown, utxoDeposited,
|
||||
utxoWithdrawn, utxoLoopingIn,
|
||||
})
|
||||
|
||||
depMgr := buildDepositMgr(map[wire.OutPoint]fsm.StateType{
|
||||
utxoAt.OutPoint: deposit.Withdrawn,
|
||||
utxoAbove1.OutPoint: deposit.Deposited,
|
||||
utxoAbove2.OutPoint: deposit.Withdrawn,
|
||||
utxoDeposited.OutPoint: deposit.Deposited,
|
||||
utxoWithdrawn.OutPoint: deposit.Withdrawn,
|
||||
utxoLoopingIn.OutPoint: deposit.LoopingIn,
|
||||
})
|
||||
|
||||
server := &swapClientServer{
|
||||
|
|
@ -1461,22 +1461,20 @@ func TestListUnspentDeposits(t *testing.T) {
|
|||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, resp.Utxos, 2)
|
||||
require.Len(t, resp.Utxos, 1)
|
||||
got := map[string]struct{}{}
|
||||
for _, u := range resp.Utxos {
|
||||
got[u.Outpoint] = struct{}{}
|
||||
}
|
||||
_, ok1 := got[utxoBelow.OutPoint.String()]
|
||||
_, ok2 := got[utxoAbove1.OutPoint.String()]
|
||||
require.True(t, ok1)
|
||||
require.True(t, ok2)
|
||||
_, ok := got[utxoDeposited.OutPoint.String()]
|
||||
require.True(t, ok)
|
||||
})
|
||||
|
||||
// Confirmed UTXO not present in store should be included.
|
||||
t.Run("confirmed utxo not in store is included", func(t *testing.T) {
|
||||
// Confirmed UTXO not present in store should be excluded.
|
||||
t.Run("confirmed utxo not in store is excluded", func(t *testing.T) {
|
||||
// Only return a confirmed UTXO from lnd and make sure the
|
||||
// deposit manager/store doesn't know about it.
|
||||
mock.SetListUnspent([]*lnwallet.Utxo{utxoAbove2})
|
||||
mock.SetListUnspent([]*lnwallet.Utxo{utxoConfirmedUnknown})
|
||||
|
||||
// Empty store (no states for any outpoint).
|
||||
depMgr := buildDepositMgr(map[wire.OutPoint]fsm.StateType{})
|
||||
|
|
@ -1491,12 +1489,6 @@ func TestListUnspentDeposits(t *testing.T) {
|
|||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the confirmed UTXO to be included even though it
|
||||
// doesn't exist in the store yet.
|
||||
require.Len(t, resp.Utxos, 1)
|
||||
require.Equal(
|
||||
t, utxoAbove2.OutPoint.String(), resp.Utxos[0].Outpoint,
|
||||
)
|
||||
require.NotEmpty(t, resp.Utxos[0].StaticAddress)
|
||||
require.Empty(t, resp.Utxos)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue