From 2f3921ff88cf547b666b012ab4d8bf820dc81564 Mon Sep 17 00:00:00 2001 From: shum Date: Thu, 22 Oct 2026 07:42:31 +0000 Subject: [PATCH] store: end taken only when the name reads taken --- .../src/StoreService/Names/Worker.hs | 10 ++++++---- tests/Bots/StoreService/NamesWorkerTests.hs | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/simplex-store-service/src/StoreService/Names/Worker.hs b/apps/simplex-store-service/src/StoreService/Names/Worker.hs index 712411eeb0..1733905160 100644 --- a/apps/simplex-store-service/src/StoreService/Names/Worker.hs +++ b/apps/simplex-store-service/src/StoreService/Names/Worker.hs @@ -263,8 +263,8 @@ registering w@Worker {wkSender} now r@NameRegistration {nrId} = Nothing -> judge w now r Nothing -- | A register that did not go through, by its dry run's revert or once every transaction settled: registered when one mined --- with status 1 or the owner holds the name; committed again on InvalidNonce, for the page to sign again; taken on --- NameNotAvailable, NameReserved, or any revert while the name is not available; failed otherwise. +-- with status 1 or the owner holds the name; committed again on InvalidNonce, for the page to sign again; taken on any revert +-- while the name is not available at the latest block; failed otherwise, unless the dry run named the name as gone. judge :: Worker -> UTCTime -> NameRegistration -> Maybe RevertName -> IO Next judge w@Worker {wkOrders = oe@OrdersEnv {oeContracts}} now r@NameRegistration {nrReveal} reason = inTurn w r $ @@ -275,13 +275,15 @@ judge w@Worker {wkOrders = oe@OrdersEnv {oeContracts}} now r@NameRegistration {n LNotLanded -> case reason of Just RNInvalidNonce -> store w now r {nrReveal = Nothing} Just RNCommitmentTooNew -> pure (Nothing, waitUntil r $ addUTCTime chainSecond now) - Just name | name `elem` [RNNameNotAvailable, RNNameReserved] -> taken w now r _ -> case nrReveal of Just NameReveal {rvLabel} -> controllerAvailable oeContracts rvLabel >>= \case Left e -> pure (Nothing, failure r e) Right False -> taken w now r - Right True -> failed w now r reason + -- the dry run runs on the pending block, where a competitor's register that may never mine can hold the name + Right True + | reason `elem` map Just [RNNameNotAvailable, RNNameReserved] -> pure (Nothing, Retry (nrVersion r) "the dry run reverted the name as gone, but it reads available") + | otherwise -> failed w now r reason Nothing -> failed w now r reason -- | The payment is kept, and a code order's code released. diff --git a/tests/Bots/StoreService/NamesWorkerTests.hs b/tests/Bots/StoreService/NamesWorkerTests.hs index 453d0aef13..cf5bd870bd 100644 --- a/tests/Bots/StoreService/NamesWorkerTests.hs +++ b/tests/Bots/StoreService/NamesWorkerTests.hs @@ -64,6 +64,7 @@ namesWorkerTests = describe "StoreService names: worker" $ do describe "register" $ do it "ends the later of two wallets' paid orders for one name taken, with its value kept" testTwoWallets it "ends taken on any revert while the name is not available, releasing a code" testRevertTaken + it "keeps the phase on NameNotAvailable while the name still reads available, as for a pending competitor" testPendingCompetitor it "ends failed on a revert while the name is available, alerting on InsufficientAllowance and keeping a code" testRevertFailed it "clears the reveal on InvalidNonce, staying committed" testInvalidNonce it "relays no intent past its deadline, ending failed" testExpiredIntent @@ -445,6 +446,20 @@ testTwoWallets = withWorker $ \w@W {wCtx = ctx} -> do (nrPhase x, nrLive x, nrPrice x, nrPayment x, nrError x) `shouldBe` (PTaken, True, nrPrice b, nrPayment b, Nothing) length <$> sent w `shouldReturn` 1 +testPendingCompetitor :: IO () +testPendingCompetitor = withWorker $ \w@W {wCtx = ctx} -> do + (r, code) <- codeIn ctx 8 aliceOrder openPhase >>= traverseFst (revealed ctx keyA "alicebakery") + -- a competitor's register in the node's pending block, never mined + answerAvailable w True + dryRunsRevert w "NameNotAvailable(string)" $ abiTuple [Dynamic $ abiBytes "alicebakery"] + steps w r >>= retrying + stored ctx r `shouldReturn` r + pcReservedBy <$> codeOf ctx code `shouldReturn` Just (nrId r) + -- the competitor's register dropped + dryRunsPass w + void $ steps w r >>= awaiting + nrPhase <$> stored ctx r `shouldReturn` PRegistering + testRevertTaken :: IO () testRevertTaken = withWorker $ \w@W {wCtx = ctx@Ctx {cNode}} -> do (r, code) <- codeIn ctx 8 aliceOrder openPhase >>= traverseFst (revealed ctx keyA "alicebakery")