Skip to content

Commit c343ca8

Browse files
authored
Merge pull request #124 from coingaming/B1M2-5847-4
B1M-5847 Abort stuck channels at startup
2 parents b246ccd + 79a627c commit c343ca8

7 files changed

Lines changed: 74 additions & 20 deletions

File tree

btc-lsp/config/model

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ SwapIntoLn
2424
expiresAt UTCTime
2525
insertedAt UTCTime
2626
updatedAt UTCTime
27+
psbtPendingChanId Lnd.PendingChannelId Maybe
2728
UniqueSwapIntoLnFundInvUuid uuid
2829
UniqueSwapIntoLnFundAddress fundAddress
2930
deriving Eq Show Generic

btc-lsp/src/BtcLsp/Psbt/PsbtOpener.hs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
module BtcLsp.Psbt.PsbtOpener
44
( openChannelPsbt,
5+
abortChannelPsbt,
56
OpenChannelPsbtResult (..),
67
OpenUpdateEvt (..),
78
)
@@ -141,18 +142,22 @@ data OpenChannelPsbtResult = OpenChannelPsbtResult
141142
fundAsync :: Async (Either Failure Lnd.ChannelPoint)
142143
}
143144

145+
abortChannelPsbt :: Env m => Lnd.PendingChannelId -> m ()
146+
abortChannelPsbt p =
147+
void $ runExceptT $ withLndT Lnd.fundingStateStep ($ shimCancelReq p)
148+
144149
openChannelPsbt ::
145150
Env m =>
151+
Lnd.PendingChannelId ->
146152
Lock ->
147153
[PsbtUtxo] ->
148154
NodePubKey ->
149155
OnChainAddress 'Gain ->
150156
Money 'Lsp 'OnChain 'Gain ->
151157
Privacy ->
152158
ExceptT Failure m OpenChannelPsbtResult
153-
openChannelPsbt lock utxos toPubKey changeAddress lspFee private = do
159+
openChannelPsbt pcid lock utxos toPubKey changeAddress lspFee private = do
154160
chan <- lift T.newTChanIO
155-
pcid <- Lnd.newPendingChanId
156161
let openChannelRequest =
157162
openChannelReq pcid toPubKey (coerce (2 * amt)) (coerce amt) private
158163
let subUpdates u = void . T.atomically . T.writeTChan chan $ LndUpdate u
@@ -164,11 +169,11 @@ openChannelPsbt lock utxos toPubKey changeAddress lspFee private = do
164169
case res of
165170
Left e -> throwE . FailureInt . FailurePrivate $ inspect e
166171
Right _ -> do
167-
fundA <- lift . spawnLink $ runExceptT $ fundStep pcid chan
172+
fundA <- lift . spawnLink $ runExceptT $ fundStep chan
168173
pure $ OpenChannelPsbtResult chan fundA
169174
where
170175
amt = sumAmt utxos - coerce lspFee
171-
fundStep pcid chan = do
176+
fundStep chan = do
172177
upd <- T.atomically $ T.readTChan chan
173178
$(logTM) DebugS $ logStr $ "Got chan status update" <> inspect upd
174179
case upd of
@@ -179,15 +184,15 @@ openChannelPsbt lock utxos toPubKey changeAddress lspFee private = do
179184
sPsbtResp <- finalizePsbt psbt'
180185
$(logTM) DebugS $ logStr $ "Used psbt for funding:" <> inspect sPsbtResp
181186
void $ withLndT Lnd.fundingStateStep ($ psbtFinalizeReq pcid (Lnd.Psbt $ FNP.signedPsbt sPsbtResp))
182-
fundStep pcid chan
187+
fundStep chan
183188
LndUpdate (Lnd.OpenStatusUpdate _ (Just (Lnd.OpenStatusUpdateChanPending p))) -> do
184189
$(logTM) DebugS $ logStr $ "Chan is pending... mining..." <> inspect p
185-
fundStep pcid chan
190+
fundStep chan
186191
LndUpdate (Lnd.OpenStatusUpdate _ (Just (Lnd.OpenStatusUpdateChanOpen (Lnd.ChannelOpenUpdate cp)))) -> do
187192
$(logTM) DebugS $ logStr $ "Chan is open" <> inspect cp
188193
pure cp
189194
LndSubFail -> do
190-
void $ withLndT Lnd.fundingStateStep ($ shimCancelReq pcid)
195+
lift $ abortChannelPsbt pcid
191196
void $ lockUtxos (getOutPoint <$> utxos)
192197
throwE (FailureInt $ FailurePrivate "Lnd subscription failed. Trying to cancel psbt flow. Its ok if cancel fails")
193198
_ -> throwE (FailureInt $ FailurePrivate "Unexpected update")

btc-lsp/src/BtcLsp/Storage/Model.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import BtcLsp.Import.External
2121
import qualified BtcLsp.Import.Psql as Psql
2222
import Database.Persist.Quasi
2323
import Database.Persist.TH
24+
import qualified LndClient as Lnd
2425
import qualified LndClient.Data.ChannelBackup as Lnd
2526

2627
-- You can define all of your database entities in the entities file.

btc-lsp/src/BtcLsp/Storage/Model/SwapIntoLn.hs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module BtcLsp.Storage.Model.SwapIntoLn
1616
getByUuidSql,
1717
getByFundAddressSql,
1818
withLockedRowSql,
19+
getSwapsInPsbtThreadSql,
1920
UtxoInfo (..),
2021
SwapInfo (..),
2122
)
@@ -25,6 +26,7 @@ import BtcLsp.Import hiding (Storage (..))
2526
import qualified BtcLsp.Import.Psql as Psql
2627
import qualified BtcLsp.Math.Swap as Math
2728
import qualified BtcLsp.Storage.Util as Util
29+
import qualified LndClient as Lnd
2830

2931
createIgnoreSql ::
3032
( MonadIO m
@@ -58,6 +60,7 @@ createIgnoreSql userEnt fundAddr feeAndChangeAddr refundAddr expAt chanPrivacy =
5860
swapIntoLnFeeMiner = Money 0,
5961
swapIntoLnStatus = SwapWaitingFundChain,
6062
swapIntoLnPrivacy = chanPrivacy,
63+
swapIntoLnPsbtPendingChanId = Nothing,
6164
swapIntoLnExpiresAt = expAt,
6265
swapIntoLnInsertedAt = ct,
6366
swapIntoLnUpdatedAt = ct
@@ -126,16 +129,19 @@ updateInPsbtThreadSql ::
126129
( MonadIO m
127130
) =>
128131
SwapIntoLnId ->
132+
Lnd.PendingChannelId ->
129133
ReaderT Psql.SqlBackend m ()
130-
updateInPsbtThreadSql id0 = do
134+
updateInPsbtThreadSql id0 pcid = do
131135
ct <- getCurrentTime
132136
Psql.update $ \row -> do
133137
Psql.set
134138
row
135139
[ SwapIntoLnStatus
136140
Psql.=. Psql.val SwapInPsbtThread,
137141
SwapIntoLnUpdatedAt
138-
Psql.=. Psql.val ct
142+
Psql.=. Psql.val ct,
143+
SwapIntoLnPsbtPendingChanId
144+
Psql.=. Psql.val (Just pcid)
139145
]
140146
Psql.where_ $
141147
( row Psql.^. SwapIntoLnId
@@ -158,7 +164,9 @@ updateRevertInPsbtThreadSql id0 = do
158164
[ SwapIntoLnStatus
159165
Psql.=. Psql.val SwapWaitingPeer,
160166
SwapIntoLnUpdatedAt
161-
Psql.=. Psql.val ct
167+
Psql.=. Psql.val ct,
168+
SwapIntoLnPsbtPendingChanId
169+
Psql.=. Psql.val Nothing
162170
]
163171
Psql.where_ $
164172
( row Psql.^. SwapIntoLnId
@@ -180,13 +188,32 @@ updateRevertAllInPsbtThreadSql = do
180188
[ SwapIntoLnStatus
181189
Psql.=. Psql.val SwapWaitingPeer,
182190
SwapIntoLnUpdatedAt
183-
Psql.=. Psql.val ct
191+
Psql.=. Psql.val ct,
192+
SwapIntoLnPsbtPendingChanId
193+
Psql.=. Psql.val Nothing
184194
]
185195
Psql.where_
186196
( row Psql.^. SwapIntoLnStatus
187197
Psql.==. Psql.val SwapInPsbtThread
188198
)
189199

200+
getSwapsInPsbtThreadSql ::
201+
( MonadIO m
202+
) =>
203+
ReaderT
204+
Psql.SqlBackend
205+
m
206+
[Entity SwapIntoLn]
207+
getSwapsInPsbtThreadSql =
208+
Psql.select $
209+
Psql.from $ \swap -> do
210+
Psql.locking Psql.ForUpdate
211+
Psql.where_
212+
( swap Psql.^. SwapIntoLnStatus
213+
Psql.==. Psql.val SwapInPsbtThread
214+
)
215+
pure swap
216+
190217
updateExpiredSql ::
191218
( MonadIO m,
192219
KatipContext m

btc-lsp/src/BtcLsp/Thread/LnChanOpener.hs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
module BtcLsp.Thread.LnChanOpener
44
( apply,
5+
cleanupInPsbtThreadChannels,
56
)
67
where
78

@@ -14,6 +15,7 @@ import qualified BtcLsp.Storage.Model.SwapIntoLn as SwapIntoLn
1415
import qualified BtcLsp.Storage.Model.SwapUtxo as SwapUtxo
1516
import Control.Concurrent.Extra
1617
import qualified Data.Set as Set
18+
import qualified LndClient as Lnd
1719
import qualified LndClient.Data.ChannelPoint as ChannelPoint
1820
import qualified LndClient.Data.Peer as Peer
1921
import qualified LndClient.RPC.Silent as LndSilent
@@ -43,15 +45,27 @@ apply = do
4345
<$> SwapIntoLn.getSwapsWaitingPeerSql
4446
mapM_
4547
( \(swp, usr) -> do
46-
void $ runSql $ SwapIntoLn.updateInPsbtThreadSql $ entityKey swp
48+
pcid <- Lnd.newPendingChanId
49+
void $ runSql $ SwapIntoLn.updateInPsbtThreadSql (entityKey swp) pcid
4750
spawnLink $
4851
runSql $ do
49-
r <- openChanSql lock swp usr
52+
r <- openChanSql pcid lock swp usr
5053
whenLeft r $ pure $ SwapIntoLn.updateRevertInPsbtThreadSql $ entityKey swp
5154
)
5255
swaps
5356
sleep300ms
5457

58+
cleanupInPsbtThreadChannels :: Env m => m ()
59+
cleanupInPsbtThreadChannels = runSql $ do
60+
swaps <- SwapIntoLn.getSwapsInPsbtThreadSql
61+
mapM_ abortChan swaps
62+
SwapIntoLn.updateRevertAllInPsbtThreadSql
63+
where
64+
abortChan (Entity _ swp) = do
65+
case swapIntoLnPsbtPendingChanId swp of
66+
Just pcid -> lift $ PO.abortChannelPsbt pcid
67+
Nothing -> pure ()
68+
5569
--
5670
-- TODO : Do not open channel in case where
5771
-- there not is enough liquidity to perform swap.
@@ -61,18 +75,20 @@ apply = do
6175
openChanSql ::
6276
( Env m
6377
) =>
78+
Lnd.PendingChannelId ->
6479
Lock ->
6580
Entity SwapIntoLn ->
6681
Entity User ->
6782
ReaderT Psql.SqlBackend m (Either (Entity SwapIntoLn) ())
68-
openChanSql lock (Entity swapKey _) userEnt = do
83+
openChanSql pcid lock (Entity swapKey _) userEnt = do
6984
res <-
7085
SwapIntoLn.withLockedRowSql swapKey (== SwapInPsbtThread) $
7186
\swapVal -> do
7287
utxos <- SwapUtxo.getSpendableUtxosBySwapIdSql swapKey
7388
cpEither <- lift . runExceptT $ do
7489
r <-
7590
PO.openChannelPsbt
91+
pcid
7692
lock
7793
(swapUtxoToPsbtUtxo . entityVal <$> utxos)
7894
(userNodePubKey $ entityVal userEnt)

btc-lsp/src/BtcLsp/Thread/Main.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import BtcLsp.Data.AppM (runApp)
1111
import qualified BtcLsp.Data.Env as Env
1212
import BtcLsp.Import
1313
import qualified BtcLsp.Storage.Migration as Storage
14-
import qualified BtcLsp.Storage.Model.SwapIntoLn as Storage
1514
import qualified BtcLsp.Thread.BlockScanner as BlockScanner
1615
import qualified BtcLsp.Thread.Expirer as Expirer
1716
import qualified BtcLsp.Thread.LnChanOpener as LnChanOpener
@@ -72,7 +71,7 @@ apply = do
7271
$(logTM) InfoS "Running postgres migrations..."
7372
Storage.migrateAll
7473
$(logTM) InfoS "Reverting SwapInPsbtThread -> SwapWaitingPeer"
75-
void $ runSql Storage.updateRevertAllInPsbtThreadSql
74+
void LnChanOpener.cleanupInPsbtThreadChannels
7675
log <- getYesodLog
7776
pool <- getSqlPool
7877
$(logTM) InfoS "Spawning lsp threads..."

btc-lsp/test/PsbtOpenerSpec.hs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import BtcLsp.Psbt.Utils (swapUtxoToPsbtUtxo)
1111
import qualified BtcLsp.Storage.Model.SwapUtxo as SwapUtxo
1212
import qualified BtcLsp.Thread.BlockScanner as BlockScanner
1313
import Control.Concurrent.Extra
14+
import qualified LndClient as Lnd
1415
import qualified LndClient.Data.Channel as CH
1516
import qualified LndClient.Data.GetInfo as Lnd
1617
import qualified LndClient.Data.ListChannels as ListChannels
@@ -55,7 +56,8 @@ spec = do
5556
profitAddr <- genAddress LndLsp
5657
Lnd.GetInfoResponse alicePubKey _ _ <- withLndTestT LndAlice Lnd.getInfo id
5758
lock <- liftIO newLock
58-
openChanRes <- PO.openChannelPsbt lock psbtUtxos alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
59+
pcid <- Lnd.newPendingChanId
60+
openChanRes <- PO.openChannelPsbt pcid lock psbtUtxos alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
5961
void . lift . spawnLink $ do
6062
sleep1s
6163
mine 1 LndLsp
@@ -100,8 +102,9 @@ spec = do
100102
profitAddr <- genAddress LndLsp
101103
Lnd.GetInfoResponse alicePubKey _ _ <- withLndTestT LndAlice Lnd.getInfo id
102104
lock <- liftIO newLock
105+
pcid <- Lnd.newPendingChanId
103106
openChanRes <-
104-
PO.openChannelPsbt lock psbtUtxos alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
107+
PO.openChannelPsbt pcid lock psbtUtxos alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
105108
void . lift . spawnLink $ do
106109
sleep1s
107110
mine 1 LndLsp
@@ -151,13 +154,15 @@ spec = do
151154
void $ lift $ runSql $ SwapUtxo.updateRefundedSql (entityKey <$> utxos0) (TxId "dummy refund tx")
152155
let psbtUtxos0 = swapUtxoToPsbtUtxo . entityVal <$> utxos0
153156

154-
openChanRes0 <- PO.openChannelPsbt psbtFlowLock psbtUtxos0 alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
157+
pcid0 <- Lnd.newPendingChanId
158+
openChanRes0 <- PO.openChannelPsbt pcid0 psbtFlowLock psbtUtxos0 alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
155159

156160
utxos1 <- lift $ runSql $ SwapUtxo.getSpendableUtxosBySwapIdSql swp1Id
157161
void $ lift $ runSql $ SwapUtxo.updateRefundedSql (entityKey <$> utxos1) (TxId "dummy refund tx")
158162
let psbtUtxos1 = swapUtxoToPsbtUtxo . entityVal <$> utxos1
159163

160-
openChanRes1 <- PO.openChannelPsbt psbtFlowLock psbtUtxos1 alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
164+
pcid1 <- Lnd.newPendingChanId
165+
openChanRes1 <- PO.openChannelPsbt pcid1 psbtFlowLock psbtUtxos1 alicePubKey (unsafeNewOnChainAddress $ Lnd.address profitAddr) (coerce lspFee) Public
161166

162167
sleep5s
163168

0 commit comments

Comments
 (0)