Skip to content

Commit 9893935

Browse files
authored
agent: fix acceptContact inconsistent state after app restart (#1412)
1 parent 966b999 commit 9893935

File tree

4 files changed

+16
-11
lines changed

4 files changed

+16
-11
lines changed

src/Simplex/Messaging/Agent.hs

+11-6
Original file line numberDiff line numberDiff line change
@@ -687,9 +687,15 @@ allowConnectionAsync' c corrId connId confId ownConnInfo =
687687
enqueueCommand c corrId connId (Just server) $ AClientCommand $ LET confId ownConnInfo
688688
_ -> throwE $ CMD PROHIBITED "allowConnectionAsync"
689689

690+
-- TODO
691+
-- Unlike `acceptContact` (synchronous version), `acceptContactAsync` uses `unacceptInvitation` in case of error,
692+
-- because we're not taking lock here. In practice it is less likely to fail because it doesn't involve network IO,
693+
-- and also it can't be triggered by user concurrently several times in a row. It could be improved similarly to
694+
-- `acceptContact` by creating a new map for invitation locks and taking lock here, and removing `unacceptInvitation`
695+
-- while marking invitation as accepted inside "lock level transaction" after successful `joinConnAsync`.
690696
acceptContactAsync' :: AgentClient -> ACorrId -> Bool -> InvitationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AM ConnId
691697
acceptContactAsync' c corrId enableNtfs invId ownConnInfo pqSupport subMode = do
692-
Invitation {contactConnId, connReq} <- withStore c (`getInvitation` invId)
698+
Invitation {contactConnId, connReq} <- withStore c $ \db -> getInvitation db "acceptContactAsync'" invId
693699
withStore c (`getConn` contactConnId) >>= \case
694700
SomeConn _ (ContactConnection ConnData {userId} _) -> do
695701
withStore' c $ \db -> acceptInvitation db invId ownConnInfo
@@ -809,7 +815,7 @@ newConnToJoin c userId connId enableNtfs cReq pqSup = case cReq of
809815

810816
newConnToAccept :: AgentClient -> ConnId -> Bool -> ConfirmationId -> PQSupport -> AM ConnId
811817
newConnToAccept c connId enableNtfs invId pqSup = do
812-
Invitation {connReq, contactConnId} <- withStore c (`getInvitation` invId)
818+
Invitation {connReq, contactConnId} <- withStore c $ \db -> getInvitation db "newConnToAccept" invId
813819
withStore c (`getConn` contactConnId) >>= \case
814820
SomeConn _ (ContactConnection ConnData {userId} _) ->
815821
newConnToJoin c userId connId enableNtfs connReq pqSup
@@ -941,13 +947,12 @@ allowConnection' c connId confId ownConnInfo = withConnLock c connId "allowConne
941947
-- | Accept contact (ACPT command) in Reader monad
942948
acceptContact' :: AgentClient -> ConnId -> Bool -> InvitationId -> ConnInfo -> PQSupport -> SubscriptionMode -> AM SndQueueSecured
943949
acceptContact' c connId enableNtfs invId ownConnInfo pqSupport subMode = withConnLock c connId "acceptContact" $ do
944-
Invitation {contactConnId, connReq} <- withStore c (`getInvitation` invId)
950+
Invitation {contactConnId, connReq} <- withStore c $ \db -> getInvitation db "acceptContact'" invId
945951
withStore c (`getConn` contactConnId) >>= \case
946952
SomeConn _ (ContactConnection ConnData {userId} _) -> do
953+
sqSecured <- joinConn c userId connId enableNtfs connReq ownConnInfo pqSupport subMode
947954
withStore' c $ \db -> acceptInvitation db invId ownConnInfo
948-
joinConn c userId connId enableNtfs connReq ownConnInfo pqSupport subMode `catchAgentError` \err -> do
949-
withStore' c (`unacceptInvitation` invId)
950-
throwE err
955+
pure sqSecured
951956
_ -> throwE $ CMD PROHIBITED "acceptContact"
952957

953958
-- | Reject contact (RJCT command) in Reader monad

src/Simplex/Messaging/Agent/Client.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2020,7 +2020,7 @@ storeError = \case
20202020
SEConnDuplicate -> CONN DUPLICATE
20212021
SEBadConnType CRcv -> CONN SIMPLEX
20222022
SEBadConnType CSnd -> CONN SIMPLEX
2023-
SEInvitationNotFound -> CMD PROHIBITED "SEInvitationNotFound"
2023+
SEInvitationNotFound cxt invId -> CMD PROHIBITED $ "SEInvitationNotFound " <> cxt <> ", invitationId = " <> show invId
20242024
-- this error is never reported as store error,
20252025
-- it is used to wrap agent operations when "transaction-like" store access is needed
20262026
-- NOTE: network IO should NOT be used inside AgentStoreMonad

src/Simplex/Messaging/Agent/Store.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ data StoreError
623623
| -- | Confirmation not found.
624624
SEConfirmationNotFound
625625
| -- | Invitation not found
626-
SEInvitationNotFound
626+
SEInvitationNotFound String InvitationId
627627
| -- | Message not found
628628
SEMsgNotFound
629629
| -- | Command not found

src/Simplex/Messaging/Agent/Store/SQLite.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -926,9 +926,9 @@ createInvitation db gVar NewInvitation {contactConnId, connReq, recipientConnInf
926926
|]
927927
(invitationId, contactConnId, connReq, recipientConnInfo)
928928

929-
getInvitation :: DB.Connection -> InvitationId -> IO (Either StoreError Invitation)
930-
getInvitation db invitationId =
931-
firstRow invitation SEInvitationNotFound $
929+
getInvitation :: DB.Connection -> String -> InvitationId -> IO (Either StoreError Invitation)
930+
getInvitation db cxt invitationId =
931+
firstRow invitation (SEInvitationNotFound cxt invitationId) $
932932
DB.query
933933
db
934934
[sql|

0 commit comments

Comments
 (0)