packages feed

haskoin-store 0.26.6 → 0.27.0

raw patch · 4 files changed

+120/−116 lines, 4 filesdep ~haskoin-store-data

Dependency ranges changed: haskoin-store-data

Files

haskoin-store.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 63c2a0e85118148d88a0ddfbd79034b4a4a45715a820cf743c52d55ac164eb35+-- hash: 05cb5cdade7814a9d00229d0a0ad2fb0c69fbde6a4b8660b01ebd6f5be7eed36  name:           haskoin-store-version:        0.26.6+version:        0.27.0 synopsis:       Storage and index for Bitcoin and Bitcoin Cash description:    Store and index Bitcoin or Bitcoin Cash blocks, transactions, balances and unspent outputs.                 All data is available via REST API in JSON or binary format.@@ -57,7 +57,7 @@     , hashable >=1.3.0.0     , haskoin-core >=0.13.3     , haskoin-node >=0.13.0-    , haskoin-store-data ==0.26.6+    , haskoin-store-data ==0.27.0     , hedis >=0.12.13     , http-types >=0.12.3     , monad-logger >=0.3.32@@ -99,7 +99,7 @@     , haskoin-core >=0.13.3     , haskoin-node >=0.13.0     , haskoin-store-    , haskoin-store-data ==0.26.6+    , haskoin-store-data ==0.27.0     , monad-logger >=0.3.32     , mtl >=2.2.2     , nqe >=0.6.1@@ -149,7 +149,7 @@     , hashable >=1.3.0.0     , haskoin-core >=0.13.3     , haskoin-node >=0.13.0-    , haskoin-store-data ==0.26.6+    , haskoin-store-data ==0.27.0     , hedis >=0.12.13     , hspec >=2.7.1     , http-types >=0.12.3
src/Haskoin/Store.hs view
@@ -15,6 +15,8 @@     , CacheError (..)     , withCache     , connectRedis+    , isInCache+    , evictFromCache        -- * Store Reader     , StoreRead (..)
src/Haskoin/Store/Cache.hs view
@@ -21,15 +21,15 @@     , cacheNewBlock     , cacheNewTx     , cacheWriter-    , isXPubCached-    , delXPubKeys+    , isInCache+    , evictFromCache     ) where  import           Control.DeepSeq           (NFData) import           Control.Monad             (forM, forM_, forever, unless, void) import           Control.Monad.Logger      (MonadLoggerIO, logDebugS, logErrorS,                                             logInfoS, logWarnS)-import           Control.Monad.Reader      (ReaderT (..), asks)+import           Control.Monad.Reader      (ReaderT (..), ask, asks) import           Control.Monad.Trans       (lift) import           Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) import           Data.Bits                 (shift, (.&.), (.|.))@@ -84,7 +84,7 @@                                             bracket, liftIO, throwIO) import           UnliftIO.Concurrent       (threadDelay) -runRedis :: MonadLoggerIO m => Redis (Either Reply a) -> CacheT m a+runRedis :: MonadLoggerIO m => Redis (Either Reply a) -> CacheX m a runRedis action =     asks cacheConn >>= \conn ->         liftIO (Redis.runRedis conn action) >>= \case@@ -101,7 +101,8 @@         , cacheChain :: !Chain         } -type CacheT = ReaderT CacheConfig+type CacheT = ReaderT (Maybe CacheConfig)+type CacheX = ReaderT CacheConfig  data CacheError     = RedisError Reply@@ -136,13 +137,22 @@     getAddressUnspents addr start = lift . getAddressUnspents addr start     getAddressesUnspents addrs start = lift . getAddressesUnspents addrs start     getMempool = lift getMempool-    xPubBals = getXPubBalances-    xPubUnspents = getXPubUnspents-    xPubTxs = getXPubTxs+    xPubBals xpub =+        ask >>= \case+            Nothing -> lift (xPubBals xpub)+            Just cfg -> lift (runReaderT (getXPubBalances xpub) cfg)+    xPubUnspents xpub start offset limit =+        ask >>= \case+            Nothing -> lift (xPubUnspents xpub start offset limit)+            Just cfg -> lift (runReaderT (getXPubUnspents xpub start offset limit) cfg)+    xPubTxs xpub start offset limit =+        ask >>= \case+            Nothing -> lift (xPubTxs xpub start offset limit)+            Just cfg -> lift (runReaderT (getXPubTxs xpub start offset limit) cfg)     getMaxGap = lift getMaxGap     getInitialGap = lift getInitialGap -withCache :: StoreRead m => CacheConfig -> CacheT m a -> m a+withCache :: StoreRead m => (Maybe CacheConfig) -> CacheT m a -> m a withCache s f = runReaderT f s  balancesPfx :: ByteString@@ -160,7 +170,7 @@     -> Maybe BlockRef     -> Offset     -> Maybe Limit-    -> CacheT m [BlockTx]+    -> CacheX m [BlockTx] getXPubTxs xpub start offset limit = do     xpubtxt <- xpubText xpub     $(logDebugS) "Cache" $ "Getting xpub txs for " <> xpubtxt@@ -183,7 +193,7 @@                     else do                         $(logDebugS) "Cache" $                             "Using DB to return txs for xpub " <> xpubtxt-                        xPubBalsTxs bals start offset limit+                        lift $ xPubBalsTxs bals start offset limit  getXPubUnspents ::        (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)@@ -191,7 +201,7 @@     -> Maybe BlockRef     -> Offset     -> Maybe Limit-    -> CacheT m [XPubUnspent]+    -> CacheX m [XPubUnspent] getXPubUnspents xpub start offset limit = do     xpubtxt <- xpubText xpub     $(logDebugS) "Cache" $ "Getting utxo for xpub " <> xpubtxt@@ -209,11 +219,11 @@                     else do                         $(logDebugS) "Cache" $                             "Using DB to return utxo for xpub " <> xpubtxt-                        xPubBalsUnspents bals start offset limit+                        lift $ xPubBalsUnspents bals start offset limit   where     process bals = do         ops <- map snd <$> cacheGetXPubUnspents xpub start offset limit-        uns <- catMaybes <$> mapM getUnspent ops+        uns <- catMaybes <$> lift (mapM getUnspent ops)         let addrmap =                 Map.fromList $                 map (\b -> (balanceAddress (xPubBal b), xPubBalPath b)) bals@@ -240,7 +250,7 @@ getXPubBalances ::        (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)     => XPubSpec-    -> CacheT m [XPubBal]+    -> CacheX m [XPubBal] getXPubBalances xpub = do     xpubtxt <- xpubText xpub     $(logDebugS) "Cache" $ "Getting balances for xpub " <> xpubtxt@@ -255,13 +265,19 @@             $(logDebugS) "Cache" $ "Caching balances for xpub " <> xpubtxt             fst <$> newXPubC xpub -isXPubCached :: MonadLoggerIO m => XPubSpec -> CacheT m Bool+isInCache :: MonadLoggerIO m => XPubSpec -> CacheT m Bool+isInCache xpub =+    ask >>= \case+        Nothing -> return False+        Just cfg -> runReaderT (isXPubCached xpub) cfg++isXPubCached :: MonadLoggerIO m => XPubSpec -> CacheX m Bool isXPubCached = runRedis . redisIsXPubCached  redisIsXPubCached :: RedisCtx m f => XPubSpec -> m (f Bool) redisIsXPubCached xpub = Redis.exists (balancesPfx <> encode xpub) -cacheGetXPubBalances :: MonadLoggerIO m => XPubSpec -> CacheT m [XPubBal]+cacheGetXPubBalances :: MonadLoggerIO m => XPubSpec -> CacheX m [XPubBal] cacheGetXPubBalances xpub = do     bals <- runRedis $ redisGetXPubBalances xpub     touchKeys [xpub]@@ -273,7 +289,7 @@     -> Maybe BlockRef     -> Offset     -> Maybe Limit-    -> CacheT m [BlockTx]+    -> CacheX m [BlockTx] cacheGetXPubTxs xpub start offset limit = do     txs <- runRedis $ redisGetXPubTxs xpub start offset limit     touchKeys [xpub]@@ -285,7 +301,7 @@     -> Maybe BlockRef     -> Offset     -> Maybe Limit-    -> CacheT m [(BlockRef, OutPoint)]+    -> CacheX m [(BlockRef, OutPoint)] cacheGetXPubUnspents xpub start offset limit = do     uns <- runRedis $ redisGetXPubUnspents xpub start offset limit     touchKeys [xpub]@@ -442,7 +458,7 @@ maxKey :: ByteString maxKey = "max" -isAnythingCached :: MonadLoggerIO m => CacheT m Bool+isAnythingCached :: MonadLoggerIO m => CacheX m Bool isAnythingCached = runRedis $ Redis.exists maxKey  xPubAddrFunction :: DeriveType -> XPubKey -> Address@@ -464,7 +480,7 @@             x <- receive inbox             cacheWriterReact x -lockIt :: MonadLoggerIO m => ByteString -> CacheT m (Maybe Word32)+lockIt :: MonadLoggerIO m => ByteString -> CacheX m (Maybe Word32) lockIt k = do     rnd <- liftIO randomIO     go rnd >>= \case@@ -498,7 +514,7 @@             Redis.setOpts k (cs (show rnd)) opts  -unlockIt :: MonadLoggerIO m => ByteString -> Maybe Word32 -> CacheT m ()+unlockIt :: MonadLoggerIO m => ByteString -> Maybe Word32 -> CacheX m () unlockIt _ Nothing = return () unlockIt k (Just i) =     runRedis (Redis.get k) >>= \case@@ -521,8 +537,8 @@ withLock ::        (MonadLoggerIO m, MonadUnliftIO m)     => ByteString-    -> CacheT m a-    -> CacheT m (Maybe a)+    -> CacheX m a+    -> CacheX m (Maybe a) withLock k f =     bracket (lockIt k) (unlockIt k) $ \case         Just _ -> Just <$> f@@ -531,8 +547,8 @@ withLockWait ::        (MonadLoggerIO m, MonadUnliftIO m)     => ByteString-    -> CacheT m a-    -> CacheT m a+    -> CacheX m a+    -> CacheX m a withLockWait k f = do     $(logDebugS) "Cache" $ "Acquiring " <> cs k <> " lock…"     go@@ -545,7 +561,7 @@                 threadDelay r                 go -pruneDB :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheT m Integer+pruneDB :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheX m Integer pruneDB = do     isAnythingCached >>= \case         True -> do@@ -568,7 +584,7 @@                         "Pruning " <> cs (show (length ks)) <> " old xpubs"                     delXPubKeys ks -touchKeys :: MonadLoggerIO m => [XPubSpec] -> CacheT m ()+touchKeys :: MonadLoggerIO m => [XPubSpec] -> CacheX m () touchKeys xpubs = do     now <- systemSeconds <$> liftIO getSystemTime     runRedis $ redisTouchKeys now xpubs@@ -581,7 +597,7 @@ cacheWriterReact ::        (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)     => CacheWriterMessage-    -> CacheT m ()+    -> CacheX m () cacheWriterReact CacheNewBlock = newBlockC cacheWriterReact (CacheNewTx th) =     withLockWait importLockKey $ do@@ -604,7 +620,7 @@ newXPubC ::        (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)     => XPubSpec-    -> CacheT m ([XPubBal], Bool)+    -> CacheX m ([XPubBal], Bool) newXPubC xpub =     cachePrime >> do         bals <- lift $ xPubBals xpub@@ -647,7 +663,7 @@             e <- redisAddXPubTxs xpub xtxs             return $ b >> c >> d >> e >> return () -newBlockC :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheT m ()+newBlockC :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheX m () newBlockC = withLockWait importLockKey f   where     f =@@ -709,7 +725,7 @@                 Just newcachenode ->                     importBlockC (headerHash (nodeHeader newcachenode)) >> f -importBlockC :: (MonadUnliftIO m, StoreRead m, MonadLoggerIO m) => BlockHash -> CacheT m ()+importBlockC :: (MonadUnliftIO m, StoreRead m, MonadLoggerIO m) => BlockHash -> CacheX m () importBlockC bh =     lift (getBlock bh) >>= \case         Nothing -> do@@ -733,7 +749,7 @@             blockHashToHex bh         cacheSetHead bh -removeHeadC :: (StoreRead m, MonadUnliftIO m, MonadLoggerIO m) => CacheT m ()+removeHeadC :: (StoreRead m, MonadUnliftIO m, MonadLoggerIO m) => CacheX m () removeHeadC =     void . runMaybeT $ do         bh <- MaybeT cacheGetHead@@ -752,7 +768,7 @@ importMultiTxC ::        (MonadUnliftIO m, StoreRead m, MonadLoggerIO m)     => [TxData]-    -> CacheT m ()+    -> CacheX m () importMultiTxC txs = do     $(logDebugS) "Cache" $ "Processing " <> cs (show (length txs)) <> " txs…"     $(logDebugS) "Cache" $@@ -767,7 +783,7 @@     $(logDebugS) "Cache" $         "Getting unspent data for " <> cs (show (length allops)) <> " outputs…"     unspentmap <- getunspents-    gap <- getMaxGap+    gap <- lift getMaxGap     now <- systemSeconds <$> liftIO getSystemTime     let xpubs = allxpubsls addrmap     forM_ (zip [(1 :: Int) ..] xpubs) $ \(i, xpub) -> do@@ -894,7 +910,7 @@ cacheAddAddresses ::        (StoreRead m, MonadUnliftIO m, MonadLoggerIO m)     => [(Address, AddressXPub)]-    -> CacheT m ()+    -> CacheX m () cacheAddAddresses [] = $(logDebugS) "Cache" "No further addresses to add" cacheAddAddresses addrs = do     $(logDebugS) "Cache" $@@ -916,7 +932,7 @@     let xpubs = HashSet.toList . HashSet.fromList . map addressXPubSpec $ Map.elems amap     $(logDebugS) "Cache" $ "Getting xpub balances…"     xmap <- getbals xpubs-    gap <- getMaxGap+    gap <- lift getMaxGap     let notnulls = getnotnull balmap         addrs' = getNewAddrs gap xmap notnulls     cacheAddAddresses addrs'@@ -964,7 +980,7 @@             Nothing   -> []             Just bals -> addrsToAdd gap bals a -syncMempoolC :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheT m ()+syncMempoolC :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheX m () syncMempoolC = do     nodepool <- (HashSet.fromList . map blockTxHash) <$> lift getMempool     cachepool <- (HashSet.fromList . map blockTxHash) <$> cacheGetMempool@@ -989,15 +1005,15 @@             Nothing -> return (Left th)             Just tx -> return (Right tx) -cacheGetMempool :: MonadLoggerIO m => CacheT m [BlockTx]+cacheGetMempool :: MonadLoggerIO m => CacheX m [BlockTx] cacheGetMempool = runRedis redisGetMempool -cacheGetHead :: MonadLoggerIO m => CacheT m (Maybe BlockHash)+cacheGetHead :: MonadLoggerIO m => CacheX m (Maybe BlockHash) cacheGetHead = runRedis redisGetHead  cachePrime ::        (StoreRead m, MonadUnliftIO m, MonadLoggerIO m)-    => CacheT m (Maybe BlockHash)+    => CacheX m (Maybe BlockHash) cachePrime =     cacheGetHead >>= \case         Nothing -> do@@ -1014,13 +1030,13 @@                         return $ a >> b >> return (Just newhead)         Just cachehead -> return $ Just cachehead -cacheSetHead :: (MonadLoggerIO m, StoreRead m) => BlockHash -> CacheT m ()+cacheSetHead :: (MonadLoggerIO m, StoreRead m) => BlockHash -> CacheX m () cacheSetHead bh = do     $(logDebugS) "Cache" $ "Cache head set to: " <> blockHashToHex bh     runRedis (redisSetHead bh) >> return ()  cacheGetAddrsInfo ::-       MonadLoggerIO m => [Address] -> CacheT m [Maybe AddressXPub]+       MonadLoggerIO m => [Address] -> CacheX m [Maybe AddressXPub] cacheGetAddrsInfo as = runRedis (redisGetAddrsInfo as)  redisAddToMempool :: (Applicative f, RedisCtx m f) => [BlockTx] -> m (f Integer)@@ -1039,10 +1055,18 @@        (Functor f, RedisCtx m f) => Address -> AddressXPub -> m (f ()) redisSetAddrInfo a i = void <$> Redis.set (addrPfx <> encode a) (encode i) +evictFromCache ::+       (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)+    => [XPubSpec]+    -> CacheT m ()+evictFromCache xpubs = ask >>= \case+    Nothing -> return ()+    Just cfg -> void (runReaderT (delXPubKeys xpubs) cfg)+ delXPubKeys ::        (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)     => [XPubSpec]-    -> CacheT m Integer+    -> CacheX m Integer delXPubKeys [] = return 0 delXPubKeys xpubs = do     forM_ xpubs $ \x -> do@@ -1193,9 +1217,9 @@   where     f t s = BlockTx {blockTxBlock = scoreBlockRef s, blockTxHash = t} -xpubText :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => XPubSpec -> CacheT m Text+xpubText :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => XPubSpec -> CacheX m Text xpubText xpub = do-    net <- getNetwork+    net <- lift getNetwork     return . cs $ xPubExport net (xPubSpecKey xpub)  cacheNewBlock :: MonadIO m => CacheWriter -> m ()
src/Haskoin/Store/Web.hs view
@@ -18,7 +18,8 @@ import           Control.Monad.Logger          (MonadLogger, MonadLoggerIO,                                                 askLoggerIO, logInfoS,                                                 monadLoggerLog)-import           Control.Monad.Reader          (ReaderT, asks, runReaderT)+import           Control.Monad.Reader          (ReaderT, asks, local,+                                                runReaderT) import           Control.Monad.Trans           (lift) import           Control.Monad.Trans.Maybe     (MaybeT (..), runMaybeT) import           Data.Aeson                    (Encoding, ToJSON (..))@@ -58,7 +59,8 @@ import           Haskoin.Node                  (Chain, OnlinePeer (..),                                                 PeerManager, chainGetBest,                                                 managerGetPeers, sendMessage)-import           Haskoin.Store.Cache           (CacheT, delXPubKeys, withCache)+import           Haskoin.Store.Cache           (CacheT, evictFromCache,+                                                withCache) import           Haskoin.Store.Common          (Limit, Offset, PubExcept (..),                                                 StoreEvent (..), StoreRead (..),                                                 applyOffset, blockAtOrBefore,@@ -182,56 +184,43 @@  runInWebReader ::        MonadIO m-    => DatabaseReaderT m a-    -> CacheT (DatabaseReaderT m) a+    => CacheT (DatabaseReaderT m) a     -> ReaderT WebConfig m a-runInWebReader bf cf = do+runInWebReader f = do     bdb <- asks (storeDB . webStore)     mc <- asks (storeCache . webStore)-    lift $ withDatabaseReader bdb $-        case mc of-            Nothing -> bf-            Just c  -> withCache c cf+    lift $ withDatabaseReader bdb (withCache mc f) -runNoCache :: MonadIO m => DatabaseReaderT m a -> WebT m a-runNoCache f = lift $ do-    bdb <- asks (storeDB . webStore)-    lift $ withDatabaseReader bdb f+runNoCache :: MonadIO m => Bool -> ReaderT WebConfig m a -> ReaderT WebConfig m a+runNoCache False f = f+runNoCache True f =+    local (\s -> s {webStore = (webStore s) {storeCache = Nothing}}) f  instance (MonadUnliftIO m, MonadLoggerIO m) =>          StoreRead (ReaderT WebConfig m) where-    getMaxGap = runInWebReader getMaxGap getMaxGap-    getInitialGap = runInWebReader getInitialGap getInitialGap-    getNetwork = runInWebReader getNetwork getNetwork-    getBestBlock = runInWebReader getBestBlock getBestBlock-    getBlocksAtHeight height =-        runInWebReader (getBlocksAtHeight height) (getBlocksAtHeight height)-    getBlock bh = runInWebReader (getBlock bh) (getBlock bh)-    getTxData th = runInWebReader (getTxData th) (getTxData th)-    getSpender op = runInWebReader (getSpender op) (getSpender op)-    getSpenders th = runInWebReader (getSpenders th) (getSpenders th)-    getUnspent op = runInWebReader (getUnspent op) (getUnspent op)-    getBalance a = runInWebReader (getBalance a) (getBalance a)-    getBalances as = runInWebReader (getBalances as) (getBalances as)-    getMempool = runInWebReader getMempool getMempool+    getMaxGap = runInWebReader getMaxGap+    getInitialGap = runInWebReader getInitialGap+    getNetwork = runInWebReader getNetwork+    getBestBlock = runInWebReader getBestBlock+    getBlocksAtHeight height = runInWebReader (getBlocksAtHeight height)+    getBlock bh = runInWebReader (getBlock bh)+    getTxData th = runInWebReader (getTxData th)+    getSpender op = runInWebReader (getSpender op)+    getSpenders th = runInWebReader (getSpenders th)+    getUnspent op = runInWebReader (getUnspent op)+    getBalance a = runInWebReader (getBalance a)+    getBalances as = runInWebReader (getBalances as)+    getMempool = runInWebReader getMempool     getAddressesTxs addrs start limit =-        runInWebReader-            (getAddressesTxs addrs start limit)-            (getAddressesTxs addrs start limit)+        runInWebReader (getAddressesTxs addrs start limit)     getAddressesUnspents addrs start limit =-        runInWebReader-            (getAddressesUnspents addrs start limit)-            (getAddressesUnspents addrs start limit)-    xPubBals xpub = runInWebReader (xPubBals xpub) (xPubBals xpub)-    xPubSummary xpub = runInWebReader (xPubSummary xpub) (xPubSummary xpub)+        runInWebReader (getAddressesUnspents addrs start limit)+    xPubBals xpub = runInWebReader (xPubBals xpub)+    xPubSummary xpub = runInWebReader (xPubSummary xpub)     xPubUnspents xpub start offset limit =-        runInWebReader-            (xPubUnspents xpub start offset limit)-            (xPubUnspents xpub start offset limit)+        runInWebReader (xPubUnspents xpub start offset limit)     xPubTxs xpub start offset limit =-        runInWebReader-            (xPubTxs xpub start offset limit)-            (xPubTxs xpub start offset limit)+        runInWebReader (xPubTxs xpub start offset limit)  instance (MonadUnliftIO m, MonadLoggerIO m) => StoreRead (WebT m) where     getNetwork = lift getNetwork@@ -583,9 +572,7 @@     proto <- setupBin     res <-         filter (not . nullBalance . xPubBal) <$>-        if nocache-            then runNoCache (xPubBals xpub)-            else xPubBals xpub+        lift (runNoCache nocache (xPubBals xpub))     protoSerialNet proto (list . xPubBalToEncoding) res  scottyXpubTxs :: (MonadUnliftIO m, MonadLoggerIO m) => Bool -> WebT m ()@@ -597,27 +584,23 @@     limit <- getLimit full     o <- getOffset     proto <- setupBin-    txs <- xPubTxs xpub start o limit+    txs <- lift . runNoCache nocache $ xPubTxs xpub start o limit     if full         then do             txs' <--                catMaybes <$>-                if nocache-                    then runNoCache (mapM (getTransaction . blockTxHash) txs)-                    else mapM (getTransaction . blockTxHash) txs+                fmap catMaybes . lift . runNoCache nocache $+                mapM (getTransaction . blockTxHash) txs             protoSerialNet proto (list . transactionToEncoding) txs'         else protoSerial proto txs  scottyXpubEvict :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m () scottyXpubEvict =-    lift (asks (storeCache . webStore)) >>= \case-        Nothing -> S.raise ThingNotFound-        Just cache -> do-            setHeaders-            xpub <- parseXpub-            proto <- setupBin-            n <- lift $ withCache cache (delXPubKeys [xpub])-            protoSerial proto (GenericResult (n > 0))+    lift (asks (storeCache . webStore)) >>= \cache -> do+        setHeaders+        xpub <- parseXpub+        proto <- setupBin+        lift . withCache cache $ evictFromCache [xpub]+        protoSerial proto (GenericResult True)   scottyXpubUnspents :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()@@ -627,11 +610,9 @@     xpub <- parseXpub     proto <- setupBin     start <- getStart+    o <- getOffset     limit <- getLimit False-    uns <--        if nocache-            then runNoCache (xPubUnspents xpub start 0 limit)-            else xPubUnspents xpub start 0 limit+    uns <- lift . runNoCache nocache $ xPubUnspents xpub start o limit     protoSerialNet proto (list . xPubUnspentToEncoding) uns  scottyXpubSummary :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()@@ -640,10 +621,7 @@     nocache <- parseNoCache     xpub <- parseXpub     proto <- setupBin-    res <--        if nocache-            then runNoCache (xPubSummary xpub)-            else xPubSummary xpub+    res <- lift . runNoCache nocache $ xPubSummary xpub     protoSerial proto res  scottyPostTx ::