Skip to content

Commit 5d79e9e

Browse files
committed
swap: restored sanity check
Restored sanity check of the maximum htlc limit. * To check max htlc more strictly than CLN's own limits. * To prevents a tiny bit of database bloat in situations where it is guaranteed to fail.
1 parent 5c30387 commit 5d79e9e

File tree

5 files changed

+107
-0
lines changed

5 files changed

+107
-0
lines changed

clightning/clightning.go

+29
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,35 @@ func min(x, y uint64) uint64 {
266266
return y
267267
}
268268

269+
// SpendableMsat returns an estimate of the total we could send through the
270+
// channel with given scid. Falls back to the owned amount in the channel.
271+
func (cl *ClightningClient) SpendableMsat(scid string) (uint64, error) {
272+
scid = lightning.Scid(scid).ClnStyle()
273+
var res ListPeerChannelsResponse
274+
err := cl.glightning.Request(ListPeerChannelsRequest{}, &res)
275+
if err != nil {
276+
return 0, err
277+
}
278+
for _, ch := range res.Channels {
279+
if ch.ShortChannelId == scid {
280+
if err = cl.checkChannel(ch); err != nil {
281+
return 0, err
282+
}
283+
maxHtlcAmtMsat, err := cl.getMaxHtlcAmtMsat(scid, cl.nodeId)
284+
if err != nil {
285+
return 0, err
286+
}
287+
// since the max htlc limit is not always set reliably,
288+
// the check is skipped if it is not set.
289+
if maxHtlcAmtMsat == 0 {
290+
return ch.GetSpendableMsat(), nil
291+
}
292+
return min(maxHtlcAmtMsat, ch.GetSpendableMsat()), nil
293+
}
294+
}
295+
return 0, fmt.Errorf("could not find a channel with scid: %s", scid)
296+
}
297+
269298
// ReceivableMsat returns an estimate of the total we could receive through the
270299
// channel with given scid.
271300
func (cl *ClightningClient) ReceivableMsat(scid string) (uint64, error) {

lnd/client.go

+37
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,43 @@ func min(x, y uint64) uint64 {
104104
return y
105105
}
106106

107+
// SpendableMsat returns an estimate of the total we could send through the
108+
// channel with given scid.
109+
func (l *Client) SpendableMsat(scid string) (uint64, error) {
110+
s := lightning.Scid(scid)
111+
r, err := l.lndClient.ListChannels(context.Background(), &lnrpc.ListChannelsRequest{
112+
ActiveOnly: false,
113+
InactiveOnly: false,
114+
PublicOnly: false,
115+
PrivateOnly: false,
116+
})
117+
if err != nil {
118+
return 0, err
119+
}
120+
for _, ch := range r.Channels {
121+
channelShortId := lnwire.NewShortChanIDFromInt(ch.ChanId)
122+
if channelShortId.String() == s.LndStyle() {
123+
if err = l.checkChannel(ch); err != nil {
124+
return 0, err
125+
}
126+
maxHtlcAmtMsat, err := l.getMaxHtlcAmtMsat(ch.ChanId, l.pubkey)
127+
if err != nil {
128+
return 0, err
129+
}
130+
spendable := (uint64(ch.GetLocalBalance()) -
131+
ch.GetLocalConstraints().GetChanReserveSat()*1000)
132+
// since the max htlc limit is not always set reliably,
133+
// the check is skipped if it is not set.
134+
if maxHtlcAmtMsat == 0 {
135+
return spendable, nil
136+
}
137+
return min(maxHtlcAmtMsat, spendable), nil
138+
139+
}
140+
}
141+
return 0, fmt.Errorf("could not find a channel with scid: %s", scid)
142+
}
143+
107144
// ReceivableMsat returns an estimate of the total we could receive through the
108145
// channel with given scid.
109146
func (l *Client) ReceivableMsat(scid string) (uint64, error) {

swap/actions.go

+8
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,14 @@ func (r *PayFeeInvoiceAction) Execute(services *SwapServices, swap *SwapData) Ev
578578
if err != nil {
579579
return swap.HandleError(err)
580580
}
581+
sp, err := ll.SpendableMsat(swap.SwapOutRequest.Scid)
582+
if err != nil {
583+
return swap.HandleError(err)
584+
}
585+
586+
if sp <= swap.SwapOutRequest.Amount*1000 {
587+
return swap.HandleError(err)
588+
}
581589
success, failureReason, err := ll.ProbePayment(swap.SwapOutRequest.Scid, swap.SwapOutRequest.Amount*1000)
582590
if err != nil {
583591
return swap.HandleError(err)

swap/service.go

+32
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,14 @@ func (s *SwapService) SwapOut(peer string, chain string, channelId string, initi
383383
return nil, err
384384
}
385385

386+
sp, err := s.swapServices.lightning.SpendableMsat(channelId)
387+
if err != nil {
388+
return nil, err
389+
}
390+
if sp <= amtSat*1000 {
391+
return nil, fmt.Errorf("exceeding spendable amount_msat: %d", sp)
392+
}
393+
386394
success, failureReason, err := s.swapServices.lightning.ProbePayment(channelId, amtSat*1000)
387395
if err != nil {
388396
return nil, err
@@ -506,6 +514,30 @@ func (s *SwapService) OnSwapInRequestReceived(swapId *SwapId, peerId string, mes
506514
return err
507515
}
508516

517+
sp, err := s.swapServices.lightning.SpendableMsat(message.Scid)
518+
if err != nil {
519+
msg := fmt.Sprintf("from the %s peer: %s", s.swapServices.lightning.Implementation(), err.Error())
520+
// We want to tell our peer why we can not do this swap.
521+
msgBytes, msgType, err := MarshalPeerswapMessage(&CancelMessage{
522+
SwapId: swapId,
523+
Message: msg,
524+
})
525+
s.swapServices.messenger.SendMessage(peerId, msgBytes, msgType)
526+
return err
527+
}
528+
529+
if sp <= message.Amount*1000 {
530+
err = fmt.Errorf("exceeding spendable amount_msat: %d", sp)
531+
msg := fmt.Sprintf("from the %s peer: %s", s.swapServices.lightning.Implementation(), err.Error())
532+
// We want to tell our peer why we can not do this swap.
533+
msgBytes, msgType, err := MarshalPeerswapMessage(&CancelMessage{
534+
SwapId: swapId,
535+
Message: msg,
536+
})
537+
s.swapServices.messenger.SendMessage(peerId, msgBytes, msgType)
538+
return err
539+
}
540+
509541
success, failureReason, err := s.swapServices.lightning.ProbePayment(message.Scid, message.Amount*1000)
510542
if err != nil {
511543
msg := fmt.Sprintf("from the %s peer: %s", s.swapServices.lightning.Implementation(), err.Error())

swap/services.go

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ type LightningClient interface {
4949
RebalancePayment(payreq string, channel string) (preimage string, err error)
5050
CanSpend(amountMsat uint64) error
5151
Implementation() string
52+
SpendableMsat(scid string) (uint64, error)
5253
ReceivableMsat(scid string) (uint64, error)
5354
ProbePayment(scid string, amountMsat uint64) (bool, string, error)
5455
}

0 commit comments

Comments
 (0)