haskoin-store 0.18.11 → 0.19.0
raw patch · 11 files changed
+113/−126 lines, 11 files
Files
- CHANGELOG.md +4/−0
- haskoin-store.cabal +2/−2
- src/Network/Haskoin/Store/Block.hs +1/−1
- src/Network/Haskoin/Store/Data.hs +2/−3
- src/Network/Haskoin/Store/Data/Cached.hs +5/−8
- src/Network/Haskoin/Store/Data/ImportDB.hs +14/−32
- src/Network/Haskoin/Store/Data/KeyValue.hs +39/−26
- src/Network/Haskoin/Store/Data/Memory.hs +15/−28
- src/Network/Haskoin/Store/Data/RocksDB.hs +14/−11
- src/Network/Haskoin/Store/Logic.hs +14/−7
- src/Network/Haskoin/Store/Web.hs +3/−8
CHANGELOG.md view
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.19.0+### Changed+- Store mempool in single key/value pair.+ ## 0.18.11 ### Changed - Do not stream mempool.
haskoin-store.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 6be250e9b16bba227b422d9b4a7951d78ed9e1245c9b5cf413b7c319ca9579a2+-- hash: fe4dcb1be7cd549a159dc229dee4efedea2fb429d57179817b96f75c5e8400f0 name: haskoin-store-version: 0.18.11+version: 0.19.0 synopsis: Storage and index for Bitcoin and Bitcoin Cash description: Store blocks, transactions, and balances for Bitcoin or Bitcoin Cash, and make that information via REST API. category: Bitcoin, Finance, Network
src/Network/Haskoin/Store/Block.hs view
@@ -78,10 +78,10 @@ getOrphanTx = runLayered . getOrphanTx getUnspent = runLayered . getUnspent getBalance = runLayered . getBalance+ getMempool = runLayered getMempool instance (MonadResource m, MonadUnliftIO m) => StoreStream (ReaderT BlockRead m) where- getMempool = transPipe runLayered getMempool getOrphans = transPipe runLayered getOrphans getAddressUnspents a x = transPipe runLayered $ getAddressUnspents a x getAddressTxs a x = transPipe runLayered $ getAddressTxs a x
src/Network/Haskoin/Store/Data.hs view
@@ -78,6 +78,7 @@ getSpender :: OutPoint -> m (Maybe Spender) getBalance :: Address -> m (Maybe Balance) getUnspent :: OutPoint -> m (Maybe Unspent)+ getMempool :: m [(UnixTime, TxHash)] class StoreWrite m where setInit :: m ()@@ -91,8 +92,7 @@ deleteAddrTx :: Address -> BlockTx -> m () insertAddrUnspent :: Address -> Unspent -> m () deleteAddrUnspent :: Address -> Unspent -> m ()- insertMempoolTx :: TxHash -> UnixTime -> m ()- deleteMempoolTx :: TxHash -> UnixTime -> m ()+ setMempool :: [(UnixTime, TxHash)] -> m () insertOrphanTx :: Tx -> UnixTime -> m () deleteOrphanTx :: TxHash -> m () setBalance :: Balance -> m ()@@ -125,7 +125,6 @@ t = fromIntegral . blockTimestamp . blockDataHeader class StoreStream m where- getMempool :: ConduitT i (UnixTime, TxHash) m () getOrphans :: ConduitT i (UnixTime, Tx) m () getAddressUnspents :: Address -> Maybe BlockRef -> ConduitT i Unspent m () getAddressTxs :: Address -> Maybe BlockRef -> ConduitT i BlockTx m ()
src/Network/Haskoin/Store/Data/Cached.hs view
@@ -32,7 +32,7 @@ newLayeredDB blocks (Just cache) = do bulkCopy opts db cdb BalKeyS bulkCopy opts db cdb UnspentKeyB- bulkCopy opts db cdb MemKeyS+ bulkCopy opts db cdb MemKey return LayeredDB {layeredDB = blocks, layeredCache = Just cache} where BlockDB {blockDBopts = opts, blockDB = db} = blocks@@ -77,10 +77,7 @@ (MonadResource m, MonadIO m) => LayeredDB -> ConduitT i Unspent m () getUnspentsC LayeredDB {layeredDB = db} = getUnspentsDB db -getMempoolC ::- (MonadResource m, MonadUnliftIO m)- => LayeredDB- -> ConduitT i (UnixTime, TxHash) m ()+getMempoolC :: MonadIO m => LayeredDB -> m [(UnixTime, TxHash)] getMempoolC LayeredDB {layeredCache = Just db} = getMempoolDB db getMempoolC LayeredDB {layeredDB = db} = getMempoolDB db @@ -147,9 +144,6 @@ instance (MonadUnliftIO m, MonadResource m) => StoreStream (ReaderT LayeredDB m) where- getMempool = do- c <- R.ask- getMempoolC c getOrphans = do c <- R.ask getOrphansC c@@ -197,3 +191,6 @@ getBalance a = do c <- R.ask getBalanceC a c+ getMempool = do+ c <- R.ask+ getMempoolC c
src/Network/Haskoin/Store/Data/ImportDB.hs view
@@ -71,13 +71,14 @@ balOps (hBalance db) <> addrTxOps (hAddrTx db) <> addrOutOps (hAddrOut db) <>- mempoolOps (hMempool db) <>+ maybeToList (mempoolOp <$> hMempool db) <> orphanOps (hOrphans db) <> unspentOps (hUnspent db) cacheMapOps :: BlockMem -> [BatchOp] cacheMapOps db =- balOps (hBalance db) <> mempoolOps (hMempool db) <> unspentOps (hUnspent db)+ balOps (hBalance db) <> maybeToList (mempoolOp <$> hMempool db) <>+ unspentOps (hUnspent db) bestBlockOp :: Maybe BlockHash -> [BatchOp] bestBlockOp Nothing = []@@ -152,13 +153,8 @@ h a b p Nothing = deleteOp AddrOutKey {addrOutKeyA = a, addrOutKeyB = b, addrOutKeyP = p} -mempoolOps ::- HashMap UnixTime (HashMap TxHash Bool) -> [BatchOp]-mempoolOps = concatMap (uncurry f) . M.toList- where- f u = map (uncurry (g u)) . M.toList- g u t True = insertOp (MemKey u t) ()- g u t False = deleteOp (MemKey u t)+mempoolOp :: [(UnixTime, TxHash)] -> BatchOp+mempoolOp = insertOp MemKey orphanOps :: HashMap TxHash (Maybe (UnixTime, Tx)) -> [BatchOp] orphanOps = map (uncurry f) . M.toList@@ -224,13 +220,8 @@ deleteAddrUnspentI a u ImportDB {importHashMap = hm} = withBlockMem hm $ deleteAddrUnspent a u -insertMempoolTxI :: MonadIO m => TxHash -> UnixTime -> ImportDB -> m ()-insertMempoolTxI t p ImportDB {importHashMap = hm} =- withBlockMem hm $ insertMempoolTx t p--deleteMempoolTxI :: MonadIO m => TxHash -> UnixTime -> ImportDB -> m ()-deleteMempoolTxI t p ImportDB {importHashMap = hm} =- withBlockMem hm $ deleteMempoolTx t p+setMempoolI :: MonadIO m => [(UnixTime, TxHash)] -> ImportDB -> m ()+setMempoolI xs ImportDB {importHashMap = hm} = withBlockMem hm $ setMempool xs insertOrphanTxI :: MonadIO m => Tx -> UnixTime -> ImportDB -> m () insertOrphanTxI t p ImportDB {importHashMap = hm} =@@ -317,19 +308,11 @@ getMempoolI :: MonadIO m => ImportDB- -> ConduitT i (UnixTime, TxHash) m ()-getMempoolI ImportDB {importHashMap = hm, importLayeredDB = db} = do- h <- hMempool <$> readTVarIO hm- let hmap =- M.fromList $- concatMap- (\(u, l) -> map (\(t, b) -> ((u, t), b)) (M.toList l))- (M.toList h)- dmap <-- fmap M.fromList . liftIO . runResourceT . withLayeredDB db . runConduit $- getMempool .| mapC (, True) .| sinkList- let rmap = M.filter id (M.union hmap dmap)- yieldMany $ sortBy (flip compare) (M.keys rmap)+ -> m [(UnixTime, TxHash)]+getMempoolI ImportDB {importHashMap = hm, importLayeredDB = db} =+ getMempoolH <$> readTVarIO hm >>= \case+ Just xs -> return xs+ Nothing -> withLayeredDB db getMempool instance MonadIO m => StoreRead (ReaderT ImportDB m) where isInitialized = R.ask >>= isInitializedI@@ -342,6 +325,7 @@ getOrphanTx h = R.ask >>= getOrphanTxI h getUnspent a = R.ask >>= getUnspentI a getBalance a = R.ask >>= getBalanceI a+ getMempool = R.ask >>= getMempoolI instance MonadIO m => StoreWrite (ReaderT ImportDB m) where setInit = R.ask >>= setInitI@@ -355,8 +339,7 @@ deleteAddrTx a t = R.ask >>= deleteAddrTxI a t insertAddrUnspent a u = R.ask >>= insertAddrUnspentI a u deleteAddrUnspent a u = R.ask >>= deleteAddrUnspentI a u- insertMempoolTx t p = R.ask >>= insertMempoolTxI t p- deleteMempoolTx t p = R.ask >>= deleteMempoolTxI t p+ setMempool xs = R.ask >>= setMempoolI xs insertOrphanTx t p = R.ask >>= insertOrphanTxI t p deleteOrphanTx t = R.ask >>= deleteOrphanTxI t insertUnspent u = R.ask >>= insertUnspentI u@@ -364,7 +347,6 @@ setBalance b = R.ask >>= setBalanceI b instance MonadIO m => StoreStream (ReaderT ImportDB m) where- getMempool = R.ask >>= getMempoolI getOrphans = undefined getAddressUnspents a m = undefined getAddressTxs a m = undefined
src/Network/Haskoin/Store/Data/KeyValue.hs view
@@ -69,7 +69,6 @@ } instance R.Key AddrTxKey- instance R.KeyValue AddrTxKey () -- | Database key for an address output.@@ -133,7 +132,6 @@ TxKey <$> get instance R.Key TxKey- instance R.KeyValue TxKey TxData data SpenderKey@@ -156,7 +154,6 @@ return $ SpenderKey op instance R.Key SpenderKey- instance R.KeyValue SpenderKey Spender -- | Unspent output database key.@@ -186,35 +183,23 @@ return $ UnspentKey OutPoint {outPointHash = h, outPointIndex = i} instance R.Key UnspentKey- instance R.KeyValue UnspentKey UnspentVal -- | Mempool transaction database key.-data MemKey- = MemKey { memTime :: !UnixTime- , memKey :: !TxHash }- | MemKeyT { memTime :: !UnixTime }- | MemKeyS- deriving (Show, Read, Eq, Ord, Generic, Hashable)+data MemKey =+ MemKey+ deriving (Show, Read) instance Serialize MemKey where- -- 0x07 · UnixTime · TxHash- put (MemKey t h) = do- putWord8 0x07- putUnixTime t- put h- -- 0x07 · UnixTime- put (MemKeyT t) = do- putWord8 0x07- putUnixTime t -- 0x07- put MemKeyS = putWord8 0x07+ put MemKey = do+ putWord8 0x07 get = do guard . (== 0x07) =<< getWord8- MemKey <$> getUnixTime <*> get+ return MemKey instance R.Key MemKey-instance R.KeyValue MemKey ()+instance R.KeyValue MemKey [(UnixTime, TxHash)] -- | Orphan pool transaction database key. data OrphanKey@@ -270,7 +255,6 @@ HeightKey <$> get instance R.Key HeightKey- instance R.KeyValue HeightKey [BlockHash] -- | Address balance database key.@@ -293,7 +277,6 @@ BalKey <$> get instance R.Key BalKey- instance R.KeyValue BalKey BalVal -- | Key for best block in database.@@ -309,7 +292,6 @@ return BestKey instance R.Key BestKey- instance R.KeyValue BestKey BlockHash -- | Key for database version.@@ -325,5 +307,36 @@ return VersionKey instance R.Key VersionKey- instance R.KeyValue VersionKey Word32+++-- | Old mempool transaction database key.+data OldMemKey+ = OldMemKey+ { memTime :: !UnixTime+ , memKey :: !TxHash+ }+ | OldMemKeyT+ { memTime :: !UnixTime+ }+ | OldMemKeyS+ deriving (Show, Read, Eq, Ord, Generic, Hashable)++instance Serialize OldMemKey where+ -- 0x07 · UnixTime · TxHash+ put (OldMemKey t h) = do+ putWord8 0x07+ putUnixTime t+ put h+ -- 0x07 · UnixTime+ put (OldMemKeyT t) = do+ putWord8 0x07+ putUnixTime t+ -- 0x07+ put OldMemKeyS = putWord8 0x07+ get = do+ guard . (== 0x07) =<< getWord8+ OldMemKey <$> getUnixTime <*> get++instance R.Key OldMemKey+instance R.KeyValue OldMemKey ()
src/Network/Haskoin/Store/Data/Memory.hs view
@@ -1,6 +1,6 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TupleSections #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-} {-# OPTIONS_GHC -Wno-orphans #-} module Network.Haskoin.Store.Data.Memory where @@ -16,6 +16,7 @@ import qualified Data.IntMap.Strict as I import Data.List import Data.Maybe+import Data.Tuple (swap) import Haskoin import Network.Haskoin.Store.Data import Network.Haskoin.Store.Data.KeyValue@@ -35,7 +36,7 @@ , hBalance :: !(HashMap Address BalVal) , hAddrTx :: !(HashMap Address (HashMap BlockRef (HashMap TxHash Bool))) , hAddrOut :: !(HashMap Address (HashMap BlockRef (HashMap OutPoint (Maybe OutVal))))- , hMempool :: !(HashMap UnixTime (HashMap TxHash Bool))+ , hMempool :: !(Maybe [(UnixTime, TxHash)]) , hOrphans :: !(HashMap TxHash (Maybe (UnixTime, Tx))) , hInit :: !Bool } deriving (Eq, Show)@@ -52,7 +53,7 @@ , hBalance = M.empty , hAddrTx = M.empty , hAddrOut = M.empty- , hMempool = M.empty+ , hMempool = Nothing , hOrphans = M.empty , hInit = False }@@ -83,12 +84,8 @@ getBalanceH :: Address -> BlockMem -> Maybe Balance getBalanceH a = fmap (balValToBalance a) . M.lookup a . hBalance -getMempoolH :: Monad m => BlockMem -> ConduitT i (UnixTime, TxHash) m ()-getMempoolH db =- let ls =- sortBy (flip compare) . M.toList . M.map (M.keys . M.filter id) $- hMempool db- in yieldMany [(u, h) | (u, hs) <- ls, h <- hs]+getMempoolH :: BlockMem -> Maybe [(UnixTime, TxHash)]+getMempoolH = hMempool getOrphansH :: Monad m => BlockMem -> ConduitT i (UnixTime, Tx) m () getOrphansH = yieldMany . catMaybes . M.elems . hOrphans@@ -238,15 +235,8 @@ (M.singleton (unspentPoint u) Nothing)) in db {hAddrOut = M.unionWith (M.unionWith M.union) s (hAddrOut db)} -insertMempoolTxH :: TxHash -> UnixTime -> BlockMem -> BlockMem-insertMempoolTxH h u db =- let s = M.singleton u (M.singleton h True)- in db {hMempool = M.unionWith M.union s (hMempool db)}--deleteMempoolTxH :: TxHash -> UnixTime -> BlockMem -> BlockMem-deleteMempoolTxH h u db =- let s = M.singleton u (M.singleton h False)- in db {hMempool = M.unionWith M.union s (hMempool db)}+setMempoolH :: [(UnixTime, TxHash)] -> BlockMem -> BlockMem+setMempoolH xs db = db {hMempool = Just xs} insertOrphanTxH :: Tx -> UnixTime -> BlockMem -> BlockMem insertOrphanTxH tx u db =@@ -315,11 +305,11 @@ getBalance a = do v <- R.ask >>= readTVarIO return $ getBalanceH a v--instance MonadIO m => StoreStream (ReaderT (TVar BlockMem) m) where getMempool = do v <- R.ask >>= readTVarIO- getMempoolH v+ return . fromMaybe [] $ getMempoolH v++instance MonadIO m => StoreStream (ReaderT (TVar BlockMem) m) where getOrphans = do v <- R.ask >>= readTVarIO getOrphansH v@@ -370,12 +360,9 @@ deleteAddrUnspent a u = do v <- R.ask atomically $ modifyTVar v (deleteAddrUnspentH a u)- insertMempoolTx h t = do- v <- R.ask- atomically $ modifyTVar v (insertMempoolTxH h t)- deleteMempoolTx h t = do+ setMempool xs = do v <- R.ask- atomically $ modifyTVar v (deleteMempoolTxH h t)+ atomically $ modifyTVar v (setMempoolH xs) insertOrphanTx t u = do v <- R.ask atomically $ modifyTVar v (insertOrphanTxH t u)
src/Network/Haskoin/Store/Data/RocksDB.hs view
@@ -9,6 +9,7 @@ import qualified Data.ByteString.Short as B.Short import Data.IntMap (IntMap) import qualified Data.IntMap.Strict as I+import Data.Maybe (fromMaybe) import Data.Word import Database.RocksDB (DB, ReadOptions) import Database.RocksDB.Query@@ -18,16 +19,25 @@ import UnliftIO dataVersion :: Word32-dataVersion = 15+dataVersion = 16 isInitializedDB :: MonadIO m => BlockDB -> m (Either InitException Bool)-isInitializedDB BlockDB {blockDBopts = opts, blockDB = db} =+isInitializedDB bdb@BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts VersionKey >>= \case Just v | v == dataVersion -> return (Right True)+ | v == 15 -> migrate15to16 bdb | otherwise -> return (Left (IncorrectVersion v)) Nothing -> return (Right False) +migrate15to16 :: MonadIO m => BlockDB -> m (Either InitException Bool)+migrate15to16 bdb@BlockDB {blockDBopts = opts, blockDB = db} = do+ xs <- liftIO $ matchingAsList db opts OldMemKeyS+ let ys = map (\(OldMemKey t h, ()) -> (t, h)) xs+ insert db MemKey ys+ insert db VersionKey (16 :: Word32)+ isInitializedDB bdb+ setInitDB :: MonadIO m => DB -> m () setInitDB db = insert db VersionKey dataVersion @@ -66,16 +76,9 @@ getBalanceDB a BlockDB {blockDBopts = opts, blockDB = db} = fmap (balValToBalance a) <$> retrieve db opts (BalKey a) -getMempoolDB ::- (MonadIO m, MonadResource m)- => BlockDB- -> ConduitT i (UnixTime, TxHash) m ()+getMempoolDB :: MonadIO m => BlockDB -> m [(UnixTime, TxHash)] getMempoolDB BlockDB {blockDBopts = opts, blockDB = db} =- x .| mapC (uncurry f)- where- x = matching db opts MemKeyS- f (MemKey u t) () = (u, t)- f _ _ = undefined+ fromMaybe [] <$> retrieve db opts MemKey getOrphansDB :: (MonadIO m, MonadResource m)
src/Network/Haskoin/Store/Logic.hs view
@@ -230,9 +230,7 @@ -> BlockNode -> m () importBlock net b n = do- mp <-- runConduit $- getMempool .| mapC snd .| filterC (`elem` bths) .| sinkList+ mp <- filter (`elem` bths) . map snd <$> getMempool getBestBlock >>= \case Nothing | isGenesis n -> do@@ -374,7 +372,7 @@ let (d, _) = fromTransaction t insertTx d updateAddressCounts net (txAddresses t) (+ 1)- unless (confirmed br) $ insertMempoolTx (txHash tx) (memRefTime br)+ unless (confirmed br) $ insertIntoMempool (txHash tx) (memRefTime br) where uns op = getUnspent op >>= \case@@ -507,7 +505,7 @@ reduceBalance net False False a (outValue o) increaseBalance True False a (outValue o) insertTx t {txDataBlock = br}- deleteMempoolTx (txHash tx) (memRefTime (txDataBlock t))+ deleteFromMempool (txHash tx) getRecursiveTx :: (Monad m, StoreRead m, MonadLogger m) => TxHash -> m [Transaction]@@ -521,6 +519,16 @@ let ss = nub . map spenderHash $ I.elems sm concat <$> mapM getRecursiveTx ss +deleteFromMempool :: (Monad m, StoreRead m, StoreWrite m) => TxHash -> m ()+deleteFromMempool th = do+ mp <- getMempool+ setMempool $ filter ((/= th) . snd) mp++insertIntoMempool :: (Monad m, StoreRead m, StoreWrite m) => TxHash -> UnixTime -> m ()+insertIntoMempool th unixtime = do+ mp <- getMempool+ setMempool $ sortBy (flip compare) ((unixtime, th) : mp)+ deleteTx :: ( StoreRead m , StoreWrite m@@ -556,8 +564,7 @@ delOutput net (OutPoint h n) let ps = filter (/= nullOutPoint) (map prevOutput (txIn (txData t))) mapM_ (unspendOutput net) ps- unless (confirmed (txDataBlock t)) $- deleteMempoolTx h (memRefTime (txDataBlock t))+ unless (confirmed (txDataBlock t)) $ deleteFromMempool h insertTx t {txDataDeleted = True} updateAddressCounts net (txDataAddresses t) (subtract 1)
src/Network/Haskoin/Store/Web.hs view
@@ -185,6 +185,7 @@ getOrphanTx = lift . getOrphanTx getUnspent = lift . getUnspent getBalance = lift . getBalance+ getMempool = lift getMempool askDB :: Monad m => WebT m LayeredDB askDB = lift R.ask@@ -344,8 +345,7 @@ scottyMempool net = do cors proto <- setupBin- db <- askDB- txs <- liftIO . runStream db $ runConduit $ getMempoolStream .| sinkList+ txs <- map snd <$> getMempool protoSerial net proto txs scottyTransaction :: MonadLoggerIO m => Network -> WebT m ()@@ -935,7 +935,7 @@ maybe_chain_best <- timeout (5 * 1000 * 1000) $ chainGetBest ch maybe_block_best <- runMaybeT $ MaybeT . getBlock =<< MaybeT getBestBlock peers <- timeout (5 * 1000 * 1000) $ managerGetPeers mgr- maybe_mempool_last <- runConduit $ getMempool .| mapC fst .| headC+ maybe_mempool_last <- fmap fst . listToMaybe <$> getMempool now <- fromIntegral . systemSeconds <$> liftIO getSystemTime let maybe_block_time_delta = (now -) . fromIntegral . blockTimestamp . blockDataHeader <$>@@ -1184,11 +1184,6 @@ in if f z x == GT then find_idx a c else find_idx c b--getMempoolStream ::- (Monad m, StoreStream m)- => ConduitT i TxHash m ()-getMempoolStream = getMempool .| mapC snd getAddressTxsLimit :: (Monad m, StoreStream m)