Skip to content

Commit 65b8cb6

Browse files
authored
Merge pull request #694 from bhandras/cost-cleanup
loop: fix the loopout per sweep onchain cost and cleanup server cost calculation (both loopin and loopout)
2 parents 1cd4207 + 5294b4f commit 65b8cb6

File tree

10 files changed

+299
-66
lines changed

10 files changed

+299
-66
lines changed

loopdb/sqlc/batch.sql.go

+48
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

loopdb/sqlc/querier.go

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

loopdb/sqlc/queries/batch.sql

+23
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ INSERT INTO sweeps (
6262
amt = $5,
6363
completed = $6;
6464

65+
-- name: GetParentBatch :one
66+
SELECT
67+
sweep_batches.*
68+
FROM
69+
sweep_batches
70+
JOIN
71+
sweeps ON sweep_batches.id = sweeps.batch_id
72+
WHERE
73+
sweeps.swap_hash = $1
74+
AND
75+
sweeps.completed = TRUE
76+
AND
77+
sweep_batches.confirmed = TRUE;
78+
79+
-- name: GetBatchSweptAmount :one
80+
SELECT
81+
SUM(amt) AS total
82+
FROM
83+
sweeps
84+
WHERE
85+
batch_id = $1
86+
AND
87+
completed = TRUE;
6588

6689
-- name: GetBatchSweeps :many
6790
SELECT

loopin.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -919,9 +919,7 @@ func (s *loopInSwap) waitForSwapComplete(ctx context.Context,
919919
s.log.Infof("Htlc spend by tx: %v",
920920
spendDetails.SpenderTxHash)
921921

922-
err := s.processHtlcSpend(
923-
ctx, spendDetails, htlcValue, sweepFee,
924-
)
922+
err := s.processHtlcSpend(ctx, spendDetails, sweepFee)
925923
if err != nil {
926924
return err
927925
}
@@ -959,8 +957,6 @@ func (s *loopInSwap) waitForSwapComplete(ctx context.Context,
959957
switch update.State {
960958
// Swap invoice was paid, so update server cost balance.
961959
case invpkg.ContractSettled:
962-
s.cost.Server -= update.AmtPaid
963-
964960
// If invoice settlement and htlc spend happen
965961
// in the expected order, move the swap to an
966962
// intermediate state that indicates that the
@@ -977,6 +973,8 @@ func (s *loopInSwap) waitForSwapComplete(ctx context.Context,
977973

978974
invoiceFinalized = true
979975
htlcKeyRevealed = s.tryPushHtlcKey(ctx)
976+
s.cost.Server = s.AmountRequested -
977+
update.AmtPaid
980978

981979
// Canceled invoice has no effect on server cost
982980
// balance.
@@ -1023,19 +1021,14 @@ func (s *loopInSwap) tryPushHtlcKey(ctx context.Context) bool {
10231021
}
10241022

10251023
func (s *loopInSwap) processHtlcSpend(ctx context.Context,
1026-
spend *chainntnfs.SpendDetail, htlcValue,
1027-
sweepFee btcutil.Amount) error {
1024+
spend *chainntnfs.SpendDetail, sweepFee btcutil.Amount) error {
10281025

10291026
// Determine the htlc input of the spending tx and inspect the witness
10301027
// to find out whether a success or a timeout tx spent the htlc.
10311028
htlcInput := spend.SpendingTx.TxIn[spend.SpenderInputIndex]
10321029

10331030
if s.htlc.IsSuccessWitness(htlcInput.Witness) {
10341031
s.setState(loopdb.StateSuccess)
1035-
1036-
// Server swept the htlc. The htlc value can be added to the
1037-
// server cost balance.
1038-
s.cost.Server += htlcValue
10391032
} else {
10401033
// We needed another on chain tx to sweep the timeout clause,
10411034
// which we now include in our costs.

loopout.go

+11-14
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,8 @@ func (s *loopOutSwap) handlePaymentResult(result paymentResult) error {
452452
return nil
453453

454454
case result.status.State == lnrpc.Payment_SUCCEEDED:
455-
s.cost.Server += result.status.Value.ToSatoshis()
455+
s.cost.Server += result.status.Value.ToSatoshis() -
456+
s.AmountRequested
456457
s.cost.Offchain += result.status.Fee.ToSatoshis()
457458

458459
return nil
@@ -514,7 +515,7 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error {
514515
}
515516

516517
// Try to spend htlc and continue (rbf) until a spend has confirmed.
517-
spendTx, err := s.waitForHtlcSpendConfirmedV2(
518+
spend, err := s.waitForHtlcSpendConfirmedV2(
518519
globalCtx, *htlcOutpoint, htlcValue,
519520
)
520521
if err != nil {
@@ -523,27 +524,23 @@ func (s *loopOutSwap) executeSwap(globalCtx context.Context) error {
523524

524525
// If spend details are nil, we resolved the swap without waiting for
525526
// its spend, so we can exit.
526-
if spendTx == nil {
527+
if spend == nil {
527528
return nil
528529
}
529530

530531
// Inspect witness stack to see if it is a success transaction. We
531532
// don't just try to match with the hash of our sweep tx, because it
532533
// may be swept by a different (fee) sweep tx from a previous run.
533534
htlcInput, err := swap.GetTxInputByOutpoint(
534-
spendTx, htlcOutpoint,
535+
spend.Tx, htlcOutpoint,
535536
)
536537
if err != nil {
537538
return err
538539
}
539540

540541
sweepSuccessful := s.htlc.IsSuccessWitness(htlcInput.Witness)
541542
if sweepSuccessful {
542-
s.cost.Server -= htlcValue
543-
544-
s.cost.Onchain = htlcValue -
545-
btcutil.Amount(spendTx.TxOut[0].Value)
546-
543+
s.cost.Onchain = spend.OnChainFeePortion
547544
s.state = loopdb.StateSuccess
548545
} else {
549546
s.state = loopdb.StateFailSweepTimeout
@@ -1005,9 +1002,9 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
10051002
// sweep or a server revocation tx.
10061003
func (s *loopOutSwap) waitForHtlcSpendConfirmedV2(globalCtx context.Context,
10071004
htlcOutpoint wire.OutPoint, htlcValue btcutil.Amount) (
1008-
*wire.MsgTx, error) {
1005+
*sweepbatcher.SpendDetail, error) {
10091006

1010-
spendChan := make(chan *wire.MsgTx)
1007+
spendChan := make(chan *sweepbatcher.SpendDetail)
10111008
spendErrChan := make(chan error, 1)
10121009
quitChan := make(chan bool, 1)
10131010

@@ -1054,10 +1051,10 @@ func (s *loopOutSwap) waitForHtlcSpendConfirmedV2(globalCtx context.Context,
10541051
for {
10551052
select {
10561053
// Htlc spend, break loop.
1057-
case spendTx := <-spendChan:
1058-
s.log.Infof("Htlc spend by tx: %v", spendTx.TxHash())
1054+
case spend := <-spendChan:
1055+
s.log.Infof("Htlc spend by tx: %v", spend.Tx.TxHash())
10591056

1060-
return spendTx, nil
1057+
return spend, nil
10611058

10621059
// Spend notification error.
10631060
case err := <-spendErrChan:

sweepbatcher/store.go

+36
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@ type BaseDB interface {
2222
GetBatchSweeps(ctx context.Context, batchID int32) (
2323
[]sqlc.GetBatchSweepsRow, error)
2424

25+
// GetBatchSweptAmount returns the total amount of sats swept by a
26+
// (confirmed) batch.
27+
GetBatchSweptAmount(ctx context.Context, batchID int32) (int64, error)
28+
2529
// GetSweepStatus returns true if the sweep has been completed.
2630
GetSweepStatus(ctx context.Context, swapHash []byte) (bool, error)
2731

32+
// GetParentBatch fetches the parent batch of a completed sweep.
33+
GetParentBatch(ctx context.Context, swapHash []byte) (sqlc.SweepBatch,
34+
error)
35+
2836
// GetSwapUpdates fetches all the updates for a swap.
2937
GetSwapUpdates(ctx context.Context, swapHash []byte) (
3038
[]sqlc.SwapUpdate, error)
@@ -148,6 +156,34 @@ func (s *SQLStore) FetchBatchSweeps(ctx context.Context, id int32) (
148156
return sweeps, nil
149157
}
150158

159+
// TotalSweptAmount returns the total amount swept by a (confirmed) batch.
160+
func (s *SQLStore) TotalSweptAmount(ctx context.Context, id int32) (
161+
btcutil.Amount, error) {
162+
163+
amt, err := s.baseDb.GetBatchSweptAmount(ctx, id)
164+
if err != nil {
165+
return 0, err
166+
}
167+
168+
return btcutil.Amount(amt), nil
169+
}
170+
171+
// GetParentBatch fetches the parent batch of a completed sweep.
172+
func (s *SQLStore) GetParentBatch(ctx context.Context, swapHash lntypes.Hash) (
173+
*dbBatch, error) {
174+
175+
batch, err := s.baseDb.GetParentBatch(ctx, swapHash[:])
176+
if err != nil {
177+
return nil, err
178+
}
179+
180+
if err != nil {
181+
return nil, err
182+
}
183+
184+
return convertBatchRow(batch), nil
185+
}
186+
151187
// UpsertSweep inserts a sweep into the database, or updates an existing sweep
152188
// if it already exists.
153189
func (s *SQLStore) UpsertSweep(ctx context.Context, sweep *dbSweep) error {

sweepbatcher/store_mock.go

+42
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"sort"
77

8+
"github.com/btcsuite/btcd/btcutil"
89
"github.com/lightningnetwork/lnd/lntypes"
910
)
1011

@@ -123,3 +124,44 @@ func (s *StoreMock) AssertSweepStored(id lntypes.Hash) bool {
123124
_, ok := s.sweeps[id]
124125
return ok
125126
}
127+
128+
// GetParentBatch returns the parent batch of a swap.
129+
func (s *StoreMock) GetParentBatch(ctx context.Context, swapHash lntypes.Hash) (
130+
*dbBatch, error) {
131+
132+
for _, sweep := range s.sweeps {
133+
if sweep.SwapHash == swapHash {
134+
batch, ok := s.batches[sweep.BatchID]
135+
if !ok {
136+
return nil, errors.New("batch not found")
137+
}
138+
return &batch, nil
139+
}
140+
}
141+
142+
return nil, errors.New("batch not found")
143+
}
144+
145+
// TotalSweptAmount returns the total amount of BTC that has been swept from a
146+
// batch.
147+
func (s *StoreMock) TotalSweptAmount(ctx context.Context, batchID int32) (
148+
btcutil.Amount, error) {
149+
150+
batch, ok := s.batches[batchID]
151+
if !ok {
152+
return 0, errors.New("batch not found")
153+
}
154+
155+
if batch.State != batchConfirmed && batch.State != batchClosed {
156+
return 0, nil
157+
}
158+
159+
var total btcutil.Amount
160+
for _, sweep := range s.sweeps {
161+
if sweep.BatchID == batchID {
162+
total += sweep.Amount
163+
}
164+
}
165+
166+
return 0, nil
167+
}

0 commit comments

Comments
 (0)