packages feed

haskoin-store 1.5.16 → 1.6.2

raw patch · 11 files changed

+319/−340 lines, 11 filesdep ~haskoin-coredep ~haskoin-nodedep ~haskoin-store-dataPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: haskoin-core, haskoin-node, haskoin-store-data, hedis, rocksdb-haskell-jprupp, rocksdb-query

API changes (from Hackage documentation)

- Haskoin.Store.BlockStore: instance Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreReadBase (Haskoin.Store.BlockStore.BlockT m)
- Haskoin.Store.BlockStore: instance GHC.Exception.Type.Exception Haskoin.Store.BlockStore.BlockException
- Haskoin.Store.BlockStore: instance GHC.Show.Show Haskoin.Store.BlockStore.BlockException
- Haskoin.Store.BlockStore: instance GHC.Show.Show Haskoin.Store.BlockStore.PendingTx
- Haskoin.Store.Cache: instance GHC.Exception.Type.Exception Haskoin.Store.Cache.CacheError
- Haskoin.Store.Cache: instance GHC.Generics.Generic Haskoin.Store.Cache.AddressXPub
- Haskoin.Store.Cache: instance GHC.Generics.Generic Haskoin.Store.Cache.CacheError
- Haskoin.Store.Cache: instance GHC.Show.Show Haskoin.Store.Cache.AddressXPub
- Haskoin.Store.Cache: instance GHC.Show.Show Haskoin.Store.Cache.CacheError
- Haskoin.Store.Common: instance Data.Default.Class.Default Haskoin.Store.Common.Limits
- Haskoin.Store.Common: instance GHC.Show.Show Haskoin.Store.Common.Limits
- Haskoin.Store.Common: instance GHC.Show.Show Haskoin.Store.Common.Start
- Haskoin.Store.Database.Reader: instance Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreReadBase (Haskoin.Store.Database.Reader.DatabaseReaderT m)
- Haskoin.Store.Database.Types: [address] :: BalKey -> !Address
- Haskoin.Store.Database.Types: [hash] :: BlockKey -> BlockHash
- Haskoin.Store.Database.Types: [height] :: HeightKey -> BlockHeight
- Haskoin.Store.Database.Types: [outpoint] :: UnspentKey -> !OutPoint
- Haskoin.Store.Database.Types: [short] :: TxKey -> (Word32, Word16)
- Haskoin.Store.Database.Types: [tx] :: AddrTxKey -> !TxRef
- Haskoin.Store.Database.Types: [txid] :: UnspentKey -> !TxHash
- Haskoin.Store.Database.Types: instance Data.Default.Class.Default Haskoin.Store.Database.Types.BalVal
- Haskoin.Store.Database.Types: instance Database.RocksDB.Query.KeyValue Haskoin.Store.Database.Types.VersionKey GHC.Word.Word32
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.AddrOutKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.AddrTxKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.BalKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.BalVal
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.BestKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.BlockKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.HeightKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.OutVal
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.TxKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.UnspentKey
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.UnspentVal
- Haskoin.Store.Database.Types: instance GHC.Generics.Generic Haskoin.Store.Database.Types.VersionKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.AddrOutKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.BalKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.BalVal
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.BestKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.BlockKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.HeightKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.MemKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.OutVal
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.TxKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.UnspentKey
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.UnspentVal
- Haskoin.Store.Database.Types: instance GHC.Read.Read Haskoin.Store.Database.Types.VersionKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.AddrOutKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.AddrTxKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.BalKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.BalVal
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.BestKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.BlockKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.HeightKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.MemKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.OutVal
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.TxKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.UnspentKey
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.UnspentVal
- Haskoin.Store.Database.Types: instance GHC.Show.Show Haskoin.Store.Database.Types.VersionKey
- Haskoin.Store.Database.Writer: instance Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreReadBase (Haskoin.Store.Database.Writer.WriterT m)
- Haskoin.Store.Database.Writer: instance Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreWrite (Haskoin.Store.Database.Writer.WriterT m)
- Haskoin.Store.Logic: instance GHC.Exception.Type.Exception Haskoin.Store.Logic.ImportException
- Haskoin.Store.Logic: instance GHC.Show.Show Haskoin.Store.Logic.ImportException
- Haskoin.Store.Web: instance Data.Default.Class.Default Haskoin.Store.Web.WebLimits
- Haskoin.Store.Web: instance GHC.Show.Show Haskoin.Store.Web.SerialAs
- Haskoin.Store.Web: instance GHC.Show.Show Haskoin.Store.Web.WebLimits
+ Haskoin.Store.BlockStore: instance GHC.Internal.Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreReadBase (Haskoin.Store.BlockStore.BlockT m)
+ Haskoin.Store.BlockStore: instance GHC.Internal.Exception.Type.Exception Haskoin.Store.BlockStore.BlockException
+ Haskoin.Store.BlockStore: instance GHC.Internal.Show.Show Haskoin.Store.BlockStore.BlockException
+ Haskoin.Store.BlockStore: instance GHC.Internal.Show.Show Haskoin.Store.BlockStore.PendingTx
+ Haskoin.Store.Cache: instance GHC.Internal.Exception.Type.Exception Haskoin.Store.Cache.CacheError
+ Haskoin.Store.Cache: instance GHC.Internal.Generics.Generic Haskoin.Store.Cache.AddressXPub
+ Haskoin.Store.Cache: instance GHC.Internal.Generics.Generic Haskoin.Store.Cache.CacheError
+ Haskoin.Store.Cache: instance GHC.Internal.Show.Show Haskoin.Store.Cache.AddressXPub
+ Haskoin.Store.Cache: instance GHC.Internal.Show.Show Haskoin.Store.Cache.CacheError
+ Haskoin.Store.Common: instance Data.Default.Internal.Default Haskoin.Store.Common.Limits
+ Haskoin.Store.Common: instance GHC.Internal.Show.Show Haskoin.Store.Common.Limits
+ Haskoin.Store.Common: instance GHC.Internal.Show.Show Haskoin.Store.Common.Start
+ Haskoin.Store.Database.Reader: instance GHC.Internal.Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreReadBase (Haskoin.Store.Database.Reader.DatabaseReaderT m)
+ Haskoin.Store.Database.Types: instance Data.Default.Internal.Default Haskoin.Store.Database.Types.BalVal
+ Haskoin.Store.Database.Types: instance Database.RocksDB.Query.KeyValue Haskoin.Store.Database.Types.VersionKey GHC.Internal.Word.Word32
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.AddrOutKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.AddrTxKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.BalKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.BalVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.BestKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.BlockKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.HeightKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.OutVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.TxKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.UnspentKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.UnspentVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Generics.Generic Haskoin.Store.Database.Types.VersionKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.AddrOutKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.BalKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.BalVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.BestKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.BlockKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.HeightKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.MemKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.OutVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.TxKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.UnspentKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.UnspentVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Read.Read Haskoin.Store.Database.Types.VersionKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.AddrOutKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.AddrTxKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.BalKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.BalVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.BestKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.BlockKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.HeightKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.MemKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.OutVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.TxKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.UnspentKey
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.UnspentVal
+ Haskoin.Store.Database.Types: instance GHC.Internal.Show.Show Haskoin.Store.Database.Types.VersionKey
+ Haskoin.Store.Database.Writer: instance GHC.Internal.Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreReadBase (Haskoin.Store.Database.Writer.WriterT m)
+ Haskoin.Store.Database.Writer: instance GHC.Internal.Control.Monad.IO.Class.MonadIO m => Haskoin.Store.Common.StoreWrite (Haskoin.Store.Database.Writer.WriterT m)
+ Haskoin.Store.Logic: instance GHC.Internal.Exception.Type.Exception Haskoin.Store.Logic.ImportException
+ Haskoin.Store.Logic: instance GHC.Internal.Show.Show Haskoin.Store.Logic.ImportException
+ Haskoin.Store.Web: instance Data.Default.Internal.Default Haskoin.Store.Web.WebLimits
+ Haskoin.Store.Web: instance GHC.Internal.Show.Show Haskoin.Store.Web.SerialAs
+ Haskoin.Store.Web: instance GHC.Internal.Show.Show Haskoin.Store.Web.WebLimits
- Haskoin.Store.Database.Reader: createDataMetrics :: MonadIO m => Stats -> m DataMetrics
+ Haskoin.Store.Database.Reader: createDataMetrics :: Stats -> IO DataMetrics
- Haskoin.Store.Database.Types: TxKey :: TxHash -> TxKey
+ Haskoin.Store.Database.Types: TxKey :: !TxHash -> TxKey
- Haskoin.Store.Database.Types: TxKeyS :: (Word32, Word16) -> TxKey
+ Haskoin.Store.Database.Types: TxKeyS :: !(Word32, Word16) -> TxKey
- Haskoin.Store.Database.Types: [script] :: OutVal -> !ByteString
+ Haskoin.Store.Database.Types: [script] :: UnspentVal -> !ByteString
- Haskoin.Store.Database.Types: [value] :: OutVal -> !Word64
+ Haskoin.Store.Database.Types: [value] :: UnspentVal -> !Word64
- Haskoin.Store.Database.Types: toUnspent :: Ctx -> AddrOutKey -> OutVal -> Unspent
+ Haskoin.Store.Database.Types: toUnspent :: Ctx -> AddrOutKey -> OutVal -> Maybe Unspent

Files

haskoin-store.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.38.0.+-- This file has been generated from package.yaml by hpack version 0.39.6. -- -- see: https://github.com/sol/hpack  name:           haskoin-store-version:        1.5.16+version:        1.6.2 synopsis:       Storage and index for Bitcoin and Bitcoin Cash description:    Please see the README on GitHub at <https://github.com/jprupp/haskoin-store#readme> category:       Bitcoin, Finance, Network@@ -52,10 +52,10 @@     , deepseq >=1.4.4.0     , hashable >=1.3.0.0     , hashtables >=1.2.4.2-    , haskoin-core >=1.0.0-    , haskoin-node >=1.0.0-    , haskoin-store-data ==1.5.16-    , hedis >=0.12.13+    , haskoin-core >=1.3.0+    , haskoin-node >=1.4.3+    , haskoin-store-data ==1.6.0+    , hedis >=0.16.1     , http-types >=0.12.3     , lens >=4.18.1     , monad-control >=1.0.2.3@@ -64,8 +64,8 @@     , network >=3.1.1.1     , nqe >=0.6.5     , random >=1.1-    , rocksdb-haskell-jprupp >=2.1.3-    , rocksdb-query >=0.4.0+    , rocksdb-haskell-jprupp >=2.3.0+    , rocksdb-query >=0.6.0     , scotty >=0.22     , statsd-rupp >=0.4     , stm >=2.5.0.0@@ -105,11 +105,11 @@     , filepath     , hashable >=1.3.0.0     , hashtables >=1.2.4.2-    , haskoin-core >=1.0.0-    , haskoin-node >=1.0.0+    , haskoin-core >=1.3.0+    , haskoin-node >=1.4.3     , haskoin-store-    , haskoin-store-data ==1.5.16-    , hedis >=0.12.13+    , haskoin-store-data ==1.6.0+    , hedis >=0.16.1     , http-types >=0.12.3     , lens >=4.18.1     , monad-control >=1.0.2.3@@ -119,8 +119,8 @@     , nqe >=0.6.5     , optparse-applicative     , random >=1.1-    , rocksdb-haskell-jprupp >=2.1.3-    , rocksdb-query >=0.4.0+    , rocksdb-haskell-jprupp >=2.3.0+    , rocksdb-query >=0.6.0     , scotty >=0.22     , statsd-rupp >=0.4     , stm >=2.5.0.0@@ -164,11 +164,11 @@     , deepseq >=1.4.4.0     , hashable >=1.3.0.0     , hashtables >=1.2.4.2-    , haskoin-core >=1.0.0-    , haskoin-node >=1.0.0+    , haskoin-core >=1.3.0+    , haskoin-node >=1.4.3     , haskoin-store-    , haskoin-store-data ==1.5.16-    , hedis >=0.12.13+    , haskoin-store-data ==1.6.0+    , hedis >=0.16.1     , hspec >=2.7.1     , http-types >=0.12.3     , lens >=4.18.1@@ -178,8 +178,8 @@     , network >=3.1.1.1     , nqe >=0.6.5     , random >=1.1-    , rocksdb-haskell-jprupp >=2.1.3-    , rocksdb-query >=0.4.0+    , rocksdb-haskell-jprupp >=2.3.0+    , rocksdb-query >=0.6.0     , scotty >=0.22     , statsd-rupp >=0.4     , stm >=2.5.0.0
src/Haskoin/Store.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DuplicateRecordFields #-}+ module Haskoin.Store   ( Store (..),     StoreConfig (..),
src/Haskoin/Store/BlockStore.hs view
@@ -126,7 +126,6 @@   ( Chain,     OnlinePeer (..),     Peer (..),-    PeerException (..),     PeerMgr,     chainBlockMain,     chainGetAncestor,@@ -269,7 +268,7 @@ setHeadersHeight :: (MonadIO m) => BlockT m () setHeadersHeight = void $ runMaybeT $ do   m <- MaybeT (asks (.metrics))-  n <- chainGetBest =<< asks (.config.chain)+  n <- liftIO . chainGetBest =<< asks (.config.chain)   setGauge m.headers (fromIntegral n.height)  setPendingTxs :: (MonadIO m) => BlockT m ()@@ -281,7 +280,7 @@ setPeersConnected :: (MonadIO m) => BlockT m () setPeersConnected = void $ runMaybeT $ do   m <- MaybeT (asks (.metrics))-  p <- getPeers =<< asks (.config.peerMgr)+  p <- liftIO . getPeers =<< asks (.config.peerMgr)   setGauge m.peers (length p)  setMempoolSize :: (MonadIO m) => BlockT m ()@@ -473,7 +472,7 @@       $(logErrorS) "BlockStore" "Block database uninitialized"       throwIO Uninitialized     Just bb -> do-      cb <- asks (.config.chain) >>= chainGetBest+      cb <- asks (.config.chain) >>= liftIO . chainGetBest       if headerHash cb.header == bb         then clearSyncingState >> return True         else return False@@ -494,7 +493,7 @@       $(logDebugS) "BlockStore" $         "Requesting mempool from peer: " <> p.label       atomically . modifyTVar m $ HashSet.insert p.label-      MMempool `sendMessage` p+      liftIO $ MMempool `sendMessage` p  processBlock ::   (MonadUnliftIO m, MonadLoggerIO m) =>@@ -508,9 +507,9 @@       $(logErrorS) "BlockStore" $         "Non-syncing peer "           <> peer.label-          <> " sent me a block: "+          <> " sent block "           <> blockHashToHex blockhash-      PeerMisbehaving "Sent unexpected block" `killPeer` peer+      killPeer peer       mzero   node <-     getBlockNode blockhash >>= \case@@ -519,14 +518,14 @@         $(logErrorS) "BlockStore" $           "Peer "             <> peer.label-            <> " sent unknown block: "+            <> " sent unknown block "             <> blockHashToHex blockhash-        PeerMisbehaving "Sent unknown block" `killPeer` peer+        killPeer peer         mzero   $(logDebugS) "BlockStore" $-    "Processing block: "+    "Processing block "       <> blockText node Nothing-      <> " from peer: "+      <> " from peer "       <> peer.label   net <- lift getNetwork   ctx <- lift getCtx@@ -557,7 +556,7 @@           <> peer.label           <> ": "           <> cs (show e)-      killPeer (PeerMisbehaving (show e)) peer+      killPeer peer  setSyncingBlocks ::   (MonadReader BlockStore m, MonadIO m) =>@@ -607,8 +606,9 @@   (MonadLoggerIO m, MonadReader BlockStore m) =>   BlockHash ->   m (Maybe BlockNode)-getBlockNode blockhash =-  chainGetBlock blockhash =<< asks (.config.chain)+getBlockNode blockhash = do+  ch <- asks (.config.chain)+  liftIO $ chainGetBlock ch blockhash  processNoBlocks ::   (MonadLoggerIO m) =>@@ -626,7 +626,7 @@         <> blockHashToHex h         <> " not found by peer: "         <> p.label-  killPeer (PeerMisbehaving "Did not find requested block(s)") p+  killPeer p  processTx :: (MonadLoggerIO m) => Peer -> Tx -> BlockT m () processTx p tx = guardMempool $ do@@ -832,22 +832,22 @@ pruneMempool :: (MonadLoggerIO m) => BlockT m () pruneMempool =   guardMempool . notify Nothing $ do-  days <- asks (.config.mempoolTimeout)-  when (days > 0) $ do-    mempool <- reverse <$> getMempool-    time <- (floor . utcTimeToPOSIXSeconds) <$> liftIO getCurrentTime-    let thresh = time - (fromIntegral days * 24 * 60 * 60)-        txs = take 1000 $ map snd $ takeWhile ((< thresh) . fst) mempool-    net <- getNetwork-    ctx <- getCtx-    when (length txs > 0) $ do-      $(logInfoS) "BlockStore" $-        "Deleting " <> cs (show (length txs)) <> " old transactions from mempool"-      runImport net ctx (mapM_ (deleteUnconfirmedTx False) txs) >>= \case-        Left e ->-          $(logErrorS) "BlockStore" $-            "Error pruning mempool: " <> cs (show e)-        Right () -> return ()+    days <- asks (.config.mempoolTimeout)+    when (days > 0) $ do+      mempool <- reverse <$> getMempool+      time <- (floor . utcTimeToPOSIXSeconds) <$> liftIO getCurrentTime+      let thresh = time - (fromIntegral days * 24 * 60 * 60)+          txs = take 1000 $ map snd $ takeWhile ((< thresh) . fst) mempool+      net <- getNetwork+      ctx <- getCtx+      when (length txs > 0) $ do+        $(logInfoS) "BlockStore" $+          "Deleting " <> cs (show (length txs)) <> " old transactions from mempool"+        runImport net ctx (mapM_ (deleteUnconfirmedTx False) txs) >>= \case+          Left e ->+            $(logErrorS) "BlockStore" $+              "Error pruning mempool: " <> cs (show e)+          Right () -> return ()  processTxs ::   (MonadLoggerIO m) =>@@ -908,7 +908,7 @@       let inv = if net.segWit then InvWitnessTx else InvTx           vec = map (InvVector inv . (.get)) xs           msg = MGetData (GetData vec)-      msg `sendMessage` p+      liftIO $ msg `sendMessage` p  touchPeer ::   ( MonadIO m,@@ -940,7 +940,7 @@         when (now `diffUTCTime` t > peer_time_out) $ do           $(logErrorS) "BlockStore" $             "Syncing peer timeout: " <> p.label-          killPeer PeerTimeout p+          killPeer p  revertToMainChain :: (MonadLoggerIO m) => BlockT m () revertToMainChain = do@@ -948,7 +948,7 @@   ch <- asks (.config.chain)   net <- getNetwork   ctx <- getCtx-  chainBlockMain h ch >>= \x -> unless x $ do+  liftIO (chainBlockMain ch h) >>= \x -> unless x $ do     $(logWarnS) "BlockStore" $       "Reverting best block: "         <> blockHashToHex h@@ -972,7 +972,7 @@         $(logErrorS) "BlockStore" "No best block set"         throwIO Uninitialized   ch <- asks (.config.chain)-  chainGetBlock bb ch >>= \case+  liftIO (chainGetBlock ch bb) >>= \case     Just x -> return x     Nothing -> do       $(logErrorS) "BlockStore" $@@ -992,7 +992,7 @@             throwIO Uninitialized       hs -> return $ last hs   ch <- asks (.config.chain)-  chainGetBlock bb ch >>= \case+  liftIO (chainGetBlock ch bb) >>= \case     Just x -> return x     Nothing -> do       $(logErrorS) "BlockStore" $@@ -1028,7 +1028,7 @@             <> " blocks from peer: "             <> p.label         addSyncingBlocks $ map (headerHash . (.header)) bns-        MGetData (GetData iv) `sendMessage` p+        liftIO $ MGetData (GetData iv) `sendMessage` p   where     getiv bns = do       w <- asks (.config.net.segWit)@@ -1036,12 +1036,12 @@           f = InvVector i . (.get) . headerHash . (.header)       return $ map f bns     getbh =-      chainGetBest =<< asks (.config.chain)+      liftIO . chainGetBest =<< asks (.config.chain)     sel bb bh = do       let sh = geth bb bh       t <- top sh bh       ch <- asks (.config.chain)-      ps <- chainGetParents (bb.height + 1) t ch+      ps <- liftIO $ chainGetParents ch (bb.height + 1) t       return $         if 500 > length ps           then ps <> [bh]@@ -1060,7 +1060,7 @@   m BlockNode findAncestor height target = do   ch <- asks (.config.chain)-  chainGetAncestor height target ch >>= \case+  liftIO (chainGetAncestor ch height target) >>= \case     Just ancestor -> return ancestor     Nothing -> do       let h = headerHash target.header@@ -1086,7 +1086,7 @@     reset_it box = do       atomically $ writeTVar box Nothing       $(logDebugS) "BlockStore" $ "Releasing peer: " <> p.label-      setFree p+      liftIO $ setFree p  trySetPeer :: (MonadLoggerIO m) => Peer -> BlockT m Bool trySetPeer p =@@ -1095,7 +1095,7 @@     Nothing -> set_it   where     set_it =-      setBusy p >>= \case+      liftIO (setBusy p) >>= \case         False -> return False         True -> do           $(logDebugS) "BlockStore" $@@ -1126,7 +1126,7 @@         False -> recurse ps         True -> syncMe     online_peer = do-      ops <- getPeers =<< asks (.config.peerMgr)+      ops <- liftIO . getPeers =<< asks (.config.peerMgr)       let ps = map (.mailbox) ops       recurse ps 
src/Haskoin/Store/Cache.hs view
@@ -56,6 +56,7 @@ import Data.HashSet qualified as HashSet import Data.IntMap.Strict qualified as I import Data.List (sort)+import Data.List.NonEmpty qualified as NonEmpty import Data.Map.Strict qualified as Map import Data.Maybe   ( catMaybes,@@ -629,9 +630,9 @@     xs <- fxs     return       [ (k, v)-        | (k', v') <- xs,-          let k = fromRight undefined $ decode k',-          let v = fromRight undefined $ decode v'+      | (k', v') <- xs,+        let k = fromRight undefined $ decode k',+        let v = fromRight undefined $ decode v'       ]  data CacheWriterMessage@@ -718,7 +719,10 @@               Redis.SetOpts                 { Redis.setSeconds = Just 300,                   Redis.setMilliseconds = Nothing,-                  Redis.setCondition = Just Redis.Nx+                  Redis.setUnixSeconds = Nothing,+                  Redis.setUnixMilliseconds = Nothing,+                  Redis.setCondition = Just Redis.Nx,+                  Redis.setKeepTTL = False                 }         Redis.setOpts l "locked" opts @@ -728,12 +732,15 @@         Redis.SetOpts           { Redis.setSeconds = Just 300,             Redis.setMilliseconds = Nothing,-            Redis.setCondition = Just Redis.Xx+            Redis.setUnixSeconds = Nothing,+            Redis.setUnixMilliseconds = Nothing,+            Redis.setCondition = Just Redis.Xx,+            Redis.setKeepTTL = False           }   Redis.setOpts l "locked" opts  unlockIt :: (MonadLoggerIO m) => ByteString -> CacheX m ()-unlockIt l = void $ runRedis (Redis.del [l])+unlockIt l = void . runRedis . Redis.del $ NonEmpty.singleton l  withLock ::   (MonadLoggerIO m, MonadUnliftIO m) =>@@ -861,10 +868,14 @@       Redis.SetOpts         { Redis.setSeconds = Just 600,           Redis.setMilliseconds = Nothing,-          Redis.setCondition = Just Redis.Nx+          Redis.setUnixSeconds = Nothing,+          Redis.setUnixMilliseconds = Nothing,+          Redis.setCondition = Just Redis.Nx,+          Redis.setKeepTTL = False         }     red = Redis.setOpts key "1" opts-    unset_index y = when y . void . runRedis $ Redis.del [key]+    unset_index y =+      when y . void . runRedis . Redis.del $ NonEmpty.singleton key     set_index = do       conn <- asks (.redis)       liftIO (Redis.runRedis conn red) <&> isRight@@ -877,7 +888,7 @@     Nothing -> return False     Just bb -> do       ch <- asks (.chain)-      cb <- chainGetBest ch+      cb <- liftIO $ chainGetBest ch       return $ cb.height > 0 && headerHash cb.header == bb  newBlockC ::@@ -908,18 +919,18 @@         Just best_block_hash -> get_block_node best_block_hash     get_block_node block_hash = do       ch <- asks (.chain)-      chainGetBlock block_hash ch+      liftIO $ chainGetBlock ch block_hash     get_blocks left_node right_node = do       ch <- asks (.chain)-      split_node <- chainGetSplitBlock left_node right_node ch+      split_node <- liftIO $ chainGetSplitBlock ch left_node right_node       let split_node_hash = headerHash split_node.header           right_node_hash = headerHash right_node.header       if split_node_hash == right_node_hash         then return []         else do           let fork_height = split_node.height + 1-          left_parents <- chainGetParents fork_height left_node ch-          right_parents <- chainGetParents fork_height right_node ch+          left_parents <- liftIO $ chainGetParents ch fork_height left_node+          right_parents <- liftIO $ chainGetParents ch fork_height right_node           let blocks = reverse left_parents <> right_parents <> pure right_node           return $ map (headerHash . (.header)) blocks @@ -1251,8 +1262,10 @@  redisRemFromMempool ::   (Applicative f, RedisCtx m f) => [TxHash] -> m (f Integer)-redisRemFromMempool [] = return (pure 0)-redisRemFromMempool xs = zrem mempoolSetKey $ map encode xs+redisRemFromMempool xs =+  case NonEmpty.nonEmpty xs of+    Nothing -> return (pure 0)+    Just xs' -> zrem mempoolSetKey $ NonEmpty.map encode xs'  redisSetAddrInfo ::   (Functor f, RedisCtx m f) => Address -> AddressXPub -> m (f ())@@ -1287,13 +1300,13 @@   where     go addrs = do       addrcount <--        case addrs of-          [] -> return (pure 0)-          _ -> Redis.del (map ((addrPfx <>) . encode) addrs)-      txsetcount <- Redis.del [txSetPfx <> encode xpub]-      utxocount <- Redis.del [utxoPfx <> encode xpub]-      balcount <- Redis.del [balancesPfx <> encode xpub]-      x <- Redis.zrem maxKey [encode xpub]+        case NonEmpty.nonEmpty addrs of+          Nothing -> return (pure 0)+          Just addrs' -> Redis.del $ NonEmpty.map ((addrPfx <>) . encode) addrs'+      txsetcount <- Redis.del $ NonEmpty.singleton (txSetPfx <> encode xpub)+      utxocount <- Redis.del $ NonEmpty.singleton (utxoPfx <> encode xpub)+      balcount <- Redis.del $ NonEmpty.singleton (balancesPfx <> encode xpub)+      x <- Redis.zrem maxKey $ NonEmpty.singleton (encode xpub)       return $ do         _ <- x         addrs' <- addrcount@@ -1311,8 +1324,10 @@  redisRemXPubTxs ::   (Applicative f, RedisCtx m f) => XPubSpec -> [TxHash] -> m (f Integer)-redisRemXPubTxs _ [] = return (pure 0)-redisRemXPubTxs xpub txhs = zrem (txSetPfx <> encode xpub) (map encode txhs)+redisRemXPubTxs xpub txhs =+  case NonEmpty.nonEmpty txhs of+    Nothing -> return (pure 0)+    Just txhs' -> zrem (txSetPfx <> encode xpub) (NonEmpty.map encode txhs')  redisAddXPubUnspents ::   (Applicative f, RedisCtx m f) =>@@ -1330,23 +1345,26 @@ redisRemXPubUnspents _ [] =   return (pure 0) redisRemXPubUnspents xpub ops =-  zrem (utxoPfx <> encode xpub) (map encode ops)+  case NonEmpty.nonEmpty ops of+    Nothing -> return (pure 0)+    Just ops' -> zrem (utxoPfx <> encode xpub) (NonEmpty.map encode ops')  redisAddXPubBalances ::   (Monad f, RedisCtx m f) => XPubSpec -> [XPubBal] -> m (f ())-redisAddXPubBalances _ [] = return (pure ())-redisAddXPubBalances xpub bals = do-  xs <- mapM (uncurry (Redis.hset (balancesPfx <> encode xpub))) entries-  ys <- forM bals $ \b ->-    redisSetAddrInfo-      b.balance.address-      AddressXPub-        { spec = xpub,-          path = b.path-        }-  return $ sequence_ xs >> sequence_ ys-  where-    entries = map (\b -> (encode b.path, encode b.balance)) bals+redisAddXPubBalances xpub bals =+  case NonEmpty.nonEmpty bals of+    Nothing -> return (pure ())+    Just bals' -> do+      let bs = NonEmpty.map (\b -> (encode b.path, encode b.balance)) bals'+      Redis.hset (balancesPfx <> encode xpub) bs+      ys <- forM bals' $ \b ->+        redisSetAddrInfo+          b.balance.address+          AddressXPub+            { spec = xpub,+              path = b.path+            }+      return $ sequence_ ys  redisSetHead :: (RedisCtx m f) => BlockHash -> m (f Redis.Status) redisSetHead bh = Redis.set bestBlockKey (encode bh)@@ -1375,13 +1393,13 @@   | otherwise =       zipWith f addrs list   where-    haschange = any ((== 1) . head . (.path)) xbals+    haschange = any ((== 1) . (!! 0) . (.path)) xbals     f a p = (a, AddressXPub {spec = xpub, path = p})-    dchain = head addrinfo.path-    fbals = filter ((== dchain) . head . (.path)) xbals-    maxidx = maximum (map (head . tail . (.path)) fbals)+    dchain = addrinfo.path !! 0+    fbals = filter ((== dchain) . (!! 0) . (.path)) xbals+    maxidx = maximum (map ((!! 1) . (.path)) fbals)     xpub = addrinfo.spec-    aidx = (head . tail) addrinfo.path+    aidx = addrinfo.path !! 1     ixs =       if gap > maxidx - aidx         then [maxidx + 1 .. aidx + gap]@@ -1440,8 +1458,7 @@     f t s = ((scoreBlockRef s).timestamp, t)  xpubText ::-  ( StoreReadBase m-  ) =>+  (StoreReadBase m) =>   XPubSpec ->   CacheX m Text xpubText xpub = do
src/Haskoin/Store/Database/Reader.hs view
@@ -27,16 +27,8 @@ where  import Conduit-  ( ConduitT,-    dropWhileC,-    lift,-    mapC,-    runConduit,-    sinkList,-    (.|),-  )-import Control.Monad.Except (runExceptT, throwError)-import Control.Monad.Reader (MonadReader, ReaderT, asks, runReaderT)+import Control.Monad (forM_)+import Control.Monad.Reader import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT) import Data.Bits ((.&.)) import Data.ByteString qualified as BS@@ -47,28 +39,14 @@ import Data.Ord (Down (..)) import Data.Serialize (encode) import Data.Word (Word32)-import Database.RocksDB-  ( ColumnFamily,-    Config (..),-    DB (..),-    Iterator,-    withDBCF,-    withIterCF,-  )+import Database.RocksDB hiding (withDB) import Database.RocksDB.Query-  ( insert,-    matching,-    matchingAsListCF,-    matchingSkip,-    retrieve,-    retrieveCF,-  ) import Haskoin import Haskoin.Store.Common import Haskoin.Store.Data import Haskoin.Store.Database.Types import System.Metrics.StatsD-import UnliftIO (MonadIO, MonadUnliftIO, bracket_, liftIO)+import UnliftIO  type DatabaseReaderT = ReaderT DatabaseReader @@ -96,7 +74,7 @@     dataIters :: !StatGauge   } -createDataMetrics :: (MonadIO m) => Stats -> m DataMetrics+createDataMetrics :: Stats -> IO DataMetrics createDataMetrics s = do   dataBestCount <- newStatCounter s "db.best_block" n   dataBlockCount <- newStatCounter s "db.blocks" n@@ -134,19 +112,20 @@   Maybe DataMetrics ->   DatabaseReaderT m a ->   m a-withDatabaseReader net ctx igap gap dir bloom stats f =-  withDBCF dir cfg (columnFamilyConfig bloom) $ \db -> do-    let bdb =-          DatabaseReader-            { db = db,-              maxGap = gap,-              net = net,-              initGap = igap,-              metrics = stats,-              ctx = ctx-            }-    initRocksDB bdb-    runReaderT f bdb+withDatabaseReader net ctx igap gap dir bloom stats m =+  withRunInIO $ \run ->+    withDBCF dir cfg (columnFamilyConfig bloom) $ \db -> do+      let bdb =+            DatabaseReader+              { db = db,+                maxGap = gap,+                net = net,+                initGap = igap,+                metrics = stats,+                ctx = ctx+              }+      initRocksDB bdb+      run $ runReaderT m bdb   where     cfg = def {createIfMissing = True} @@ -163,7 +142,7 @@   ]  addrTxCF :: DB -> ColumnFamily-addrTxCF = head . columnFamilies+addrTxCF db = columnFamilies db !! 0  addrOutCF :: DB -> ColumnFamily addrOutCF db = columnFamilies db !! 1@@ -183,81 +162,93 @@ balanceCF :: DB -> ColumnFamily balanceCF db = columnFamilies db !! 7 -initRocksDB :: (MonadIO m) => DatabaseReader -> m ()-initRocksDB DatabaseReader {db = db} = do-  e <--    runExceptT $-      retrieve db VersionKey >>= \case-        Just v-          | v == dataVersion -> return ()-          | otherwise -> throwError "Incorrect RocksDB database version"-        Nothing -> setInitRocksDB db-  case e of-    Left s -> error s-    Right () -> return ()+initRocksDB :: DatabaseReader -> IO ()+initRocksDB DatabaseReader {db = db} =+  retrieve db VersionKey >>= \case+    Just v+      | v == dataVersion -> return ()+      | otherwise -> error "Incorrect RocksDB database version"+    Nothing -> setInitRocksDB db -setInitRocksDB :: (MonadIO m) => DB -> m ()+setInitRocksDB :: DB -> IO () setInitRocksDB db = insert db VersionKey dataVersion  addressConduit ::-  (MonadUnliftIO m) =>+  (MonadIO m) =>   Address ->   Maybe Start ->   Iterator ->   ConduitT i TxRef (DatabaseReaderT m) ()-addressConduit a s it =-  x .| mapC (uncurry f)+addressConduit a s it = do+  pipe .| mapC (uncurry f)   where     f (AddrTxKey _ t) () = t     f _ _ = undefined-    x = case s of+    pipe = case s of       Nothing ->-        matching it (AddrTxKeyA a)+        readerC $ \_ ->+          transPipe liftIO $+            matching it (AddrTxKeyA a)       Just (AtBlock bh) ->-        matchingSkip-          it-          (AddrTxKeyA a)-          (AddrTxKeyB a (BlockRef bh maxBound))+        readerC $ \_ ->+          transPipe liftIO $+            matchingSkip+              it+              (AddrTxKeyA a)+              (AddrTxKeyB a (BlockRef bh maxBound))       Just (AtTx txh) ->         lift (getTxData txh) >>= \case           Just TxData {block = b@BlockRef {}} ->-            matchingSkip it (AddrTxKeyA a) (AddrTxKeyB a b)+            readerC $ \_ ->+              transPipe liftIO $+                matchingSkip+                  it+                  (AddrTxKeyA a)+                  (AddrTxKeyB a b)           Just TxData {block = MemRef {}} ->             let cond (AddrTxKey _ (TxRef MemRef {} th)) = th /= txh                 cond (AddrTxKey _ (TxRef BlockRef {} _)) = False                 cond _ = undefined-             in matching it (AddrTxKeyA a)-                  .| (dropWhileC (cond . fst) >> mapC id)+             in readerC $ \_ ->+                  transPipe liftIO $+                    matching it (AddrTxKeyA a)+                      .| (dropWhileC (cond . fst) >> mapC id)           Nothing -> return ()  unspentConduit ::-  (MonadUnliftIO m) =>+  (MonadIO m) =>   Ctx ->   Address ->   Maybe Start ->   Iterator ->   ConduitT i Unspent (DatabaseReaderT m) () unspentConduit ctx a s it =-  x .| mapC (uncurry (toUnspent ctx))+  x .| mapC (uncurry (toUnspent ctx)) .| concatC   where     x = case s of       Nothing ->-        matching it (AddrOutKeyA a)+        readerC $ \_ -> transPipe liftIO $ matching it (AddrOutKeyA a)       Just (AtBlock h) ->-        matchingSkip-          it-          (AddrOutKeyA a)-          (AddrOutKeyB a (BlockRef h maxBound))+        readerC $ \_ ->+          transPipe liftIO $+            matchingSkip+              it+              (AddrOutKeyA a)+              (AddrOutKeyB a (BlockRef h maxBound))       Just (AtTx txh) ->         lift (getTxData txh) >>= \case           Just TxData {block = b@BlockRef {}} ->-            matchingSkip it (AddrOutKeyA a) (AddrOutKeyB a b)+            readerC $ \_ ->+              transPipe liftIO $+                matchingSkip it (AddrOutKeyA a) (AddrOutKeyB a b)           Just TxData {block = MemRef {}} ->             let cond (AddrOutKey _ MemRef {} p) = p.hash /= txh                 cond (AddrOutKey _ BlockRef {} _) = False                 cond _ = undefined-             in matching it (AddrOutKeyA a)-                  .| (dropWhileC (cond . fst) >> mapC id)+             in readerC $ \_ ->+                  transPipe liftIO $+                    matching it (AddrOutKeyA a)+                      .| (dropWhileC (cond . fst) >> mapC id)           Nothing -> return ()  withIterCFStat ::@@ -266,10 +257,16 @@   ColumnFamily ->   (Iterator -> DatabaseReaderT m a) ->   DatabaseReaderT m a-withIterCFStat db cf = bracket_ open close . withIterCF db cf+withIterCFStat db cf f = do+  m <- asks (.metrics)+  bracket_ (open m) (close m) go   where-    open = asks (.metrics) >>= mapM_ (\m -> incrementGauge m.dataIters 1)-    close = asks (.metrics) >>= mapM_ (\m -> decrementGauge m.dataIters 1)+    open (Just m) = incrementGauge m.dataIters 1+    open Nothing = return ()+    close (Just m) = decrementGauge m.dataIters 1+    close Nothing = return ()+    go = withRunInIO $ \run ->+      withIterCF db cf $ \it -> run (f it)  withManyIters ::   (MonadUnliftIO m) =>@@ -297,7 +294,7 @@    getTxData th = do     db <- asks (.db)-    retrieveCF db (txCF db) (TxKey th) >>= \case+    liftIO (retrieveCF db (txCF db) (TxKey th)) >>= \case       Nothing -> return Nothing       Just t -> do         withMetrics $ \s -> incrementCounter s.dataTxCount 1@@ -311,7 +308,7 @@   getUnspent p = do     db <- asks (.db)     ctx <- asks (.ctx)-    val <- retrieveCF db (unspentCF db) (UnspentKey p)+    val <- liftIO (retrieveCF db (unspentCF db) (UnspentKey p))     case fmap (valToUnspent ctx p) val of       Nothing -> return Nothing       Just u -> do@@ -321,20 +318,20 @@   getBalance a = do     db <- asks (.db)     withMetrics $ \s -> incrementCounter s.dataBalanceCount 1-    fmap (valToBalance a) <$> retrieveCF db (balanceCF db) (BalKey a)+    fmap (valToBalance a) <$> liftIO (retrieveCF db (balanceCF db) (BalKey a))    getMempool = do     db <- asks (.db)     withMetrics $ \s -> incrementCounter s.dataMempoolCount 1-    fromMaybe [] <$> retrieve db MemKey+    fromMaybe [] <$> liftIO (retrieve db MemKey)    getBestBlock = do     withMetrics $ \s -> incrementCounter s.dataBestCount 1-    asks (.db) >>= (`retrieve` BestKey)+    asks (.db) >>= liftIO . (`retrieve` BestKey)    getBlocksAtHeight h = do     db <- asks (.db)-    retrieveCF db (heightCF db) (HeightKey h) >>= \case+    liftIO (retrieveCF db (heightCF db) (HeightKey h)) >>= \case       Nothing -> return []       Just ls -> do         withMetrics $ \s -> incrementCounter s.dataBlockCount (length ls)@@ -342,7 +339,7 @@    getBlock h = do     db <- asks (.db)-    retrieveCF db (blockCF db) (BlockKey h) >>= \case+    liftIO (retrieveCF db (blockCF db) (BlockKey h)) >>= \case       Nothing -> return Nothing       Just b -> do         withMetrics $ \s -> incrementCounter s.dataBlockCount 1@@ -395,17 +392,16 @@    getInitialGap = asks (.initGap) -  getNumTxData i = do-    db <- asks (.db)+  getNumTxData i = ReaderT $ \r -> do     let (sk, w) = decodeTxKey i-    ls <- liftIO $ matchingAsListCF db (txCF db) (TxKeyS sk)+    ls <- liftIO $ matchingAsListCF r.db (txCF r.db) (TxKeyS sk)     let f t =           let bs = encode $ txHash t.tx               b = BS.head (BS.drop 6 bs)               w' = b .&. 0xf8            in w == w'         txs = filter f $ map snd ls-    withMetrics $ \s -> incrementCounter s.dataTxCount (length txs)+    forM_ r.metrics $ \s -> incrementCounter s.dataTxCount (length txs)     return txs    getBalances as = do@@ -416,8 +412,8 @@    xPubBals xpub = do     ctx <- asks (.ctx)-    igap <- getInitialGap-    gap <- getMaxGap+    igap <- asks (.initGap)+    gap <- asks (.maxGap)     ext1 <- derive_until_gap gap 0 (take (fromIntegral igap) (aderiv ctx 0 0))     if all nullxb ext1       then do
src/Haskoin/Store/Database/Types.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE NoFieldSelectors #-}@@ -77,38 +78,26 @@ -- | Database key for an address transaction. data AddrTxKey   = -- | key for a transaction affecting an address-    AddrTxKey-      { address :: !Address,-        tx :: !TxRef-      }+    AddrTxKey !Address !TxRef   | -- | short key that matches all entries-    AddrTxKeyA-      { address :: !Address-      }-  | AddrTxKeyB-      { address :: !Address,-        block :: !BlockRef-      }+    AddrTxKeyA !Address+  | AddrTxKeyB !Address !BlockRef   | AddrTxKeyS   deriving (Show, Eq, Ord, Generic, Hashable)  instance Serialize AddrTxKey where   -- 0x05 · Address · BlockRef · TxHash -  put-    AddrTxKey-      { address = a,-        tx = TxRef {block = b, txid = t}-      } = do-      put AddrTxKeyB {address = a, block = b}-      put t+  put (AddrTxKey a TxRef {block = b, txid = t}) = do+    put (AddrTxKeyB a b)+    put t   -- 0x05 · Address-  put AddrTxKeyA {address = a} = do+  put (AddrTxKeyA a) = do     put AddrTxKeyS     put a   -- 0x05 · Address · BlockRef-  put AddrTxKeyB {address = a, block = b} = do-    put AddrTxKeyA {address = a}+  put (AddrTxKeyB a b) = do+    put (AddrTxKeyA a)     put b   -- 0x05   put AddrTxKeyS = putWord8 0x05@@ -117,11 +106,7 @@     a <- get     b <- get     t <- get-    return-      AddrTxKey-        { address = a,-          tx = TxRef {block = b, txid = t}-        }+    return $ AddrTxKey a TxRef {block = b, txid = t}  instance Key AddrTxKey @@ -130,34 +115,25 @@ -- | Database key for an address output. data AddrOutKey   = -- | full key-    AddrOutKey-      { address :: !Address,-        block :: !BlockRef,-        outpoint :: !OutPoint-      }+    AddrOutKey !Address !BlockRef !OutPoint   | -- | short key for all spent or unspent outputs-    AddrOutKeyA-      { address :: !Address-      }-  | AddrOutKeyB-      { address :: !Address,-        block :: !BlockRef-      }+    AddrOutKeyA !Address+  | AddrOutKeyB !Address !BlockRef   | AddrOutKeyS   deriving (Show, Read, Eq, Ord, Generic, Hashable)  instance Serialize AddrOutKey where   -- 0x06 · StoreAddr · BlockRef · OutPoint -  put AddrOutKey {address = a, block = b, outpoint = p} = do-    put AddrOutKeyB {address = a, block = b}+  put (AddrOutKey a b p) = do+    put (AddrOutKeyB a b)     put p   -- 0x06 · StoreAddr · BlockRef-  put AddrOutKeyB {address = a, block = b} = do-    put AddrOutKeyA {address = a}+  put (AddrOutKeyB a b) = do+    put (AddrOutKeyA a)     put b   -- 0x06 · StoreAddr-  put AddrOutKeyA {address = a} = do+  put (AddrOutKeyA a) = do     put AddrOutKeyS     put a   -- 0x06@@ -168,18 +144,15 @@  instance Key AddrOutKey -data OutVal = OutVal-  { value :: !Word64,-    script :: !ByteString-  }+data OutVal = OutVal !Word64 !ByteString   deriving (Show, Read, Eq, Ord, Generic, Hashable, Serialize)  instance KeyValue AddrOutKey OutVal  -- | Transaction database key. data TxKey-  = TxKey {txid :: TxHash}-  | TxKeyS {short :: (Word32, Word16)}+  = TxKey !TxHash+  | TxKeyS !(Word32, Word16)   deriving (Show, Read, Eq, Ord, Generic, Hashable)  instance Serialize TxKey where@@ -200,11 +173,14 @@       wb = masked `shift` 11       bs = runPut (putWord64be wb)       g = do-        w1 <- getWord32be-        w2 <- getWord16be-        w3 <- getWord8-        return (w1, w2, w3)-      Right (w1, w2, w3) = runGet g bs+        w1' <- getWord32be+        w2' <- getWord16be+        w3' <- getWord8+        return (w1', w2', w3')+      (w1, w2, w3) =+        case runGet g bs of+          Right x -> x+          Left e -> error e    in ((w1, w2), w3)  instance Key TxKey@@ -213,19 +189,19 @@  -- | Unspent output database key. data UnspentKey-  = UnspentKey {outpoint :: !OutPoint}-  | UnspentKeyS {txid :: !TxHash}+  = UnspentKey !OutPoint+  | UnspentKeyS !TxHash   | UnspentKeyB   deriving (Show, Read, Eq, Ord, Generic, Hashable)  instance Serialize UnspentKey where   -- 0x09 · TxHash · Index-  put UnspentKey {outpoint = OutPoint {hash = h, index = i}} = do+  put (UnspentKey OutPoint {hash = h, index = i}) = do     putWord8 0x09     put h     put i   -- 0x09 · TxHash-  put UnspentKeyS {txid = t} = do+  put (UnspentKeyS t) = do     putWord8 0x09     put t   -- 0x09@@ -240,15 +216,17 @@  instance KeyValue UnspentKey UnspentVal -toUnspent :: Ctx -> AddrOutKey -> OutVal -> Unspent-toUnspent ctx AddrOutKey {..} OutVal {..} =-  Unspent-    { block = block,-      value = value,-      script = script,-      outpoint = outpoint,-      address = eitherToMaybe (scriptToAddressBS ctx script)-    }+toUnspent :: Ctx -> AddrOutKey -> OutVal -> Maybe Unspent+toUnspent ctx (AddrOutKey _address block outpoint) (OutVal value script) =+  Just+    Unspent+      { block = block,+        value = value,+        script = script,+        outpoint = outpoint,+        address = eitherToMaybe (scriptToAddressBS ctx script)+      }+toUnspent _ _ _ = Nothing  -- | Mempool transaction database key. data MemKey@@ -267,9 +245,7 @@ instance KeyValue MemKey [(UnixTime, TxHash)]  -- | Block entry database key.-newtype BlockKey = BlockKey-  { hash :: BlockHash-  }+newtype BlockKey = BlockKey BlockHash   deriving (Show, Read, Eq, Ord, Generic, Hashable)  instance Serialize BlockKey where@@ -286,9 +262,7 @@ instance KeyValue BlockKey BlockData  -- | Block height database key.-newtype HeightKey = HeightKey-  { height :: BlockHeight-  }+newtype HeightKey = HeightKey BlockHeight   deriving (Show, Read, Eq, Ord, Generic, Hashable)  instance Serialize HeightKey where@@ -306,9 +280,7 @@  -- | Address balance database key. data BalKey-  = BalKey-      { address :: !Address-      }+  = BalKey !Address   | BalKeyS   deriving (Show, Read, Eq, Ord, Generic, Hashable) @@ -328,8 +300,7 @@ instance KeyValue BalKey BalVal  -- | Key for best block in database.-data BestKey-  = BestKey+data BestKey = BestKey   deriving (Show, Read, Eq, Ord, Generic, Hashable)  instance Serialize BestKey where@@ -344,8 +315,7 @@ instance KeyValue BestKey BlockHash  -- | Key for database version.-data VersionKey-  = VersionKey+data VersionKey = VersionKey   deriving (Eq, Show, Read, Ord, Generic, Hashable)  instance Serialize VersionKey where
src/Haskoin/Store/Database/Writer.hs view
@@ -124,7 +124,7 @@       liftIO $ H.insert outputTable k (Just v)     where       k = (a, u.block, u.outpoint)-      v = OutVal {value = u.value, script = u.script}+      v = OutVal u.value u.script   deleteAddrUnspent a u =     ReaderT $ \Writer {memory = Memory {..}} ->       liftIO $ H.insert outputTable k Nothing@@ -169,7 +169,7 @@   hm <- newMemory net ctx mempool   x <- R.runReaderT f Writer {reader = bdb, memory = hm}   ops <- hashMapOps db hm-  writeBatch db ops+  liftIO $ writeBatch db ops   return x  hashMapOps :: (MonadIO m) => DB -> Memory -> m [BatchOp]@@ -229,21 +229,12 @@     f (a, b, p) (Just l) =       insertOpCF         (addrOutCF db)-        ( AddrOutKey-            { address = a,-              block = b,-              outpoint = p-            }-        )+        (AddrOutKey a b p)         l     f (a, b, p) Nothing =       deleteOpCF         (addrOutCF db)-        AddrOutKey-          { address = a,-            block = b,-            outpoint = p-          }+        (AddrOutKey a b p)  mempoolOp :: (MonadIO m) => MempoolTable -> m [BatchOp] mempoolOp t =
src/Haskoin/Store/Logic.hs view
@@ -173,12 +173,12 @@   insertBlock bd {main = False}   $(logDebugS) "BlockStore" $     "Updated as not in main chain: " <> blockHashToHex bh-  forM_ (tail tds) unConfirmTx+  forM_ (drop 1 tds) unConfirmTx   $(logDebugS) "BlockStore" $     "Unconfirmed " <> cs (show (length tds)) <> " transactions"-  deleteConfirmedTx (txHash (head tds).tx)+  deleteConfirmedTx (txHash (tds !! 0).tx)   $(logDebugS) "BlockStore" $-    "Deleted coinbase: " <> txHashToHex (txHash (head tds).tx)+    "Deleted coinbase: " <> txHashToHex (txHash (tds !! 0).tx)  checkNewBlock :: (MonadImport m) => Block -> BlockNode -> m () checkNewBlock b n =@@ -267,7 +267,7 @@   return (bd, tds)   where     ts_out_val =-      sum $ map (sum . map (.value) . (.outputs)) $ tail $ b.txs+      sum $ map (sum . map (.value) . (.outputs)) (drop 1 b.txs)     w =       let f t = (t :: Tx) {witness = []}           b' = (b :: Block) {txs = map f b.txs}
src/Haskoin/Store/Manager.hs view
@@ -98,6 +98,7 @@     MonadUnliftIO,     STM,     atomically,+    liftIO,     link,     withAsync,   )@@ -196,7 +197,7 @@   DatabaseReaderT m a ->   m a connectDB cfg f = do-  stats <- mapM createDataMetrics cfg.stats+  stats <- liftIO $ mapM createDataMetrics cfg.stats   withDatabaseReader     cfg.net     cfg.ctx@@ -347,15 +348,15 @@         MNotFound (NotFound is) -> do           let blocks =                 [ BlockHash h-                  | InvVector t h <- is,-                    t == InvBlock || t == InvWitnessBlock+                | InvVector t h <- is,+                  t == InvBlock || t == InvWitnessBlock                 ]           unless (null blocks) $ blockStoreNotFoundSTM p blocks b         MInv (Inv is) -> do           let txs =                 [ TxHash h-                  | InvVector t h <- is,-                    t == InvTx || t == InvWitnessTx+                | InvVector t h <- is,+                  t == InvTx || t == InvWitnessTx                 ]           publishSTM (StoreTxAnnounce p txs) pub           unless (null txs) $ blockStoreTxHashSTM p txs b
src/Haskoin/Store/Web.hs view
@@ -87,7 +87,6 @@   ( encodingToLazyByteString,     list,   )-import Data.Aeson.Text (encodeToLazyText) import Data.Base16.Types (assertBase16) import Data.ByteString.Base16 (decodeBase16, isBase16) import Data.ByteString.Builder (lazyByteString)@@ -120,7 +119,6 @@ import Data.Text (Text) import Data.Text qualified as T import Data.Text.Encoding qualified as T-import Data.Text.Lazy (toStrict) import Data.Text.Lazy qualified as TL import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Word (Word32, Word64)@@ -526,7 +524,7 @@     healthCheckLoop v = forever $ do       threadDelay (config.healthCheckInterval * 1000 * 1000)       runHealthCheck >>= atomically . writeTVar v-    opts = def {S.settings = settings defaultSettings}+    opts = S.defaultOptions {S.settings = settings defaultSettings}     settings = setPort config.port . setHost (fromString config.host)  getRates ::@@ -1185,15 +1183,15 @@   Tx ->   m () publishTx cfg tx = do-  ps <- getPeers cfg.store.peerMgr+  ps <- liftIO $ getPeers cfg.store.peerMgr   let c = max 1 (length ps `div` 2)   forM_ (take c ps) $ \p -> do-    sendMessage (MTx tx) p.mailbox+    liftIO $ sendMessage (MTx tx) p.mailbox     void . async $ do       threadDelay (5 * 1000 * 1000)       let v = if cfg.store.net.segWit then InvWitnessTx else InvTx           g = MGetData (GetData [InvVector v (txHash tx).get])-      sendMessage g p.mailbox+      liftIO $ sendMessage g p.mailbox  -- GET Mempool / Events -- @@ -1482,7 +1480,7 @@  getChainHeight :: (MonadUnliftIO m) => ActionT m H.BlockHeight getChainHeight =-  fmap (.height) $ chainGetBest =<< askl (.config.store.chain)+  fmap (.height) $ liftIO . chainGetBest =<< askl (.config.store.chain)  scottyBinfoUnspent :: (MonadUnliftIO m, MonadLoggerIO m) => ActionT m () scottyBinfoUnspent =@@ -2073,7 +2071,7 @@   withMetrics (.binfoQaddressfirstseen) $ do     a <- getAddress =<< S.captureParam "addr"     ch <- askl (.config.store.chain)-    bb <- chainGetBest ch+    bb <- liftIO $ chainGetBest ch     let top = bb.height         bot = 0     i <- go ch bb a bot top@@ -2093,7 +2091,7 @@         | z -> go ch bb a mid top         | otherwise -> return 0     getblocktime ch bb h =-      chainGetAncestor h bb ch >>= \case+      liftIO (chainGetAncestor ch h bb) >>= \case         Just b -> return b.header.timestamp         Nothing -> do           lift . $(logErrorS) "Web" $@@ -2331,7 +2329,7 @@ scottyBinfoGetBlockCount =   withMetrics (.binfoQgetblockcount) $ do     ch <- askl (.config.store.chain)-    bn <- chainGetBest ch+    bn <- liftIO $ chainGetBest ch     setHeaders     S.text $ TL.pack $ show bn.height @@ -2339,7 +2337,7 @@ scottyBinfoLatestHash =   withMetrics (.binfoQlatesthash) $ do     ch <- askl (.config.store.chain)-    bn <- chainGetBest ch+    bn <- liftIO $ chainGetBest ch     setHeaders     S.text $ TL.fromStrict $ H.blockHashToHex $ H.headerHash bn.header @@ -2348,7 +2346,7 @@   withMetrics (.binfoQbcperblock) $ do     ch <- askl (.config.store.chain)     net <- askl (.config.store.net)-    bn <- chainGetBest ch+    bn <- liftIO $ chainGetBest ch     setHeaders     S.text $       cs $@@ -2362,7 +2360,13 @@   withMetrics (.binfoQaddresstohash) $ do     addr <- getAddress =<< S.captureParam "addr"     setHeaders-    S.text $ encodeHexLazy $ runPutL $ serialize addr.hash160+    if+      | Just h <- addressHash160 addr ->+          S.text $ encodeHexLazy $ runPutL $ serialize h+      | Just h <- addressHash256 addr ->+          S.text $ encodeHexLazy $ runPutL $ serialize h+      | otherwise ->+          return ()  scottyBinfoHashToAddr :: (MonadUnliftIO m) => ActionT m () scottyBinfoHashToAddr =@@ -2444,7 +2448,13 @@       Nothing -> raise $ UserError "Could not decode public key"       Just pk -> return $ pubKeyAddr ctx pk     setHeaders-    S.text $ encodeHexLazy $ runPutL $ serialize addr.hash160+    if+      | Just h <- addressHash160 addr ->+          S.text $ encodeHexLazy $ runPutL $ serialize h+      | Just h <- addressHash256 addr ->+          S.text $ encodeHexLazy $ runPutL $ serialize h+      | otherwise ->+          return ()  -- GET Network Information -- @@ -2460,7 +2470,7 @@ getPeersInformation ::   (MonadLoggerIO m) => PeerMgr -> m [PeerInfo] getPeersInformation mgr =-  mapMaybe toInfo <$> getPeers mgr+  mapMaybe toInfo <$> liftIO (getPeers mgr)   where     toInfo op = do       ver <- op.version@@ -2487,7 +2497,7 @@   m BlockHealth blockHealthCheck cfg = do   let ch = cfg.store.chain-  headers <- (.height) <$> chainGetBest ch+  headers <- (.height) <$> liftIO (chainGetBest ch)   blocks <-     maybe 0 (.height)       <$> runMaybeT (MaybeT getBestBlock >>= MaybeT . getBlock)@@ -2505,7 +2515,7 @@   m TimeHealth lastBlockHealthCheck ch WebLimits {blockTimeout} = do   n <- round <$> liftIO getPOSIXTime-  t <- fromIntegral . (.header.timestamp) <$> chainGetBest ch+  t <- fromIntegral . (.header.timestamp) <$> liftIO (chainGetBest ch)   return     TimeHealth       { age = n - t,@@ -2518,7 +2528,7 @@   m TimeHealth lastTxHealthCheck WebConfig {noMempool, store = store', limits} = do   n <- round <$> liftIO getPOSIXTime-  b <- fromIntegral . (.header.timestamp) <$> chainGetBest ch+  b <- fromIntegral . (.header.timestamp) <$> liftIO (chainGetBest ch)   t <-     getMempool >>= \case       t : _ ->@@ -2554,13 +2564,11 @@   WebConfig ->   m CountHealth peerHealthCheck cfg = do-  count <- fromIntegral . length <$> getPeers cfg.store.peerMgr+  count <- fromIntegral . length <$> liftIO (getPeers cfg.store.peerMgr)   return CountHealth {min = fromIntegral cfg.minPeers, count}  healthCheck ::-  (MonadUnliftIO m, MonadLoggerIO m, StoreReadBase m) =>-  WebConfig ->-  m HealthCheck+  (MonadUnliftIO m, StoreReadBase m) => WebConfig -> m HealthCheck healthCheck cfg = do   blocks <- blockHealthCheck cfg   lastBlock <- lastBlockHealthCheck cfg.store.chain cfg.limits@@ -2568,23 +2576,19 @@   pendingTxs <- pendingTxsHealthCheck cfg   peers <- peerHealthCheck cfg   time <- round <$> liftIO getPOSIXTime-  let check =-        HealthCheck-          { network = cfg.store.net.name,-            version = cfg.version,-            ..-          }-  unless (isOK check) $ do-    let t = toStrict $ encodeToLazyText check-    $(logErrorS) "Web" $ "Health check failed: " <> t-  return check+  return+    HealthCheck+      { network = cfg.store.net.name,+        version = cfg.version,+        ..+      }  scottyDbStats :: (MonadUnliftIO m) => ActionT m () scottyDbStats =   withMetrics (.db) $ do     setHeaders     db <- askl (.config.store.db.db)-    statsM <- lift (getProperty db Stats)+    statsM <- liftIO (getProperty db Stats)     S.text $ maybe "Could not get stats" cs statsM  -----------------------
test/Haskoin/StoreSpec.hs view
@@ -18,7 +18,7 @@ import Data.ByteString.Base64 import Data.Either import Data.List (find)-import Data.Maybe (fromJust, fromMaybe, isJust, mapMaybe)+import Data.Maybe import Data.Serialize import Data.Time.Clock.POSIX import Data.Word@@ -47,7 +47,7 @@           StoreBestBlock b -> Just b           _ -> Nothing         let bestHash = last bs-        bestNodeM <- chainGetBlock bestHash testStoreChain+        bestNodeM <- liftIO $ chainGetBlock testStoreChain bestHash         bestNodeM `shouldSatisfy` isJust         let bestNode = fromJust bestNodeM             bestHeight = bestNode.height@@ -70,9 +70,8 @@           lift $ do             bd.height `shouldBe` 15             length bd.txs `shouldBe` 1-            head bd.txs `shouldBe` h1-            t1 `shouldSatisfy` isJust-            txHash (transactionData (fromJust t1)) `shouldBe` h1+            listToMaybe bd.txs `shouldBe` Just h1+            fmap (txHash . transactionData) t1 `shouldBe` Just h1  withTestStore ::   (MonadUnliftIO m) =>