{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE LambdaCase #-} {-# OPTIONS_GHC -Wno-orphans #-} module Network.Haskoin.Store.Data.RocksDB where import Conduit import Control.Monad.Reader (MonadReader, ReaderT) import qualified Control.Monad.Reader as R 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 import Haskoin import Network.Haskoin.Store.Data import Network.Haskoin.Store.Data.KeyValue import UnliftIO dataVersion :: Word32 dataVersion = 16 isInitializedDB :: MonadIO m => BlockDB -> m (Either InitException Bool) 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 getBestBlockDB :: MonadIO m => BlockDB -> m (Maybe BlockHash) getBestBlockDB BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts BestKey getBlocksAtHeightDB :: MonadIO m => BlockHeight -> BlockDB -> m [BlockHash] getBlocksAtHeightDB h BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts (HeightKey h) >>= \case Nothing -> return [] Just ls -> return ls getBlockDB :: MonadIO m => BlockHash -> BlockDB -> m (Maybe BlockData) getBlockDB h BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts (BlockKey h) getTxDataDB :: MonadIO m => TxHash -> BlockDB -> m (Maybe TxData) getTxDataDB th BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts (TxKey th) getSpenderDB :: MonadIO m => OutPoint -> BlockDB -> m (Maybe Spender) getSpenderDB op BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts $ SpenderKey op getSpendersDB :: MonadIO m => TxHash -> BlockDB -> m (IntMap Spender) getSpendersDB th BlockDB {blockDBopts = opts, blockDB = db} = I.fromList . map (uncurry f) <$> liftIO (matchingAsList db opts (SpenderKeyS th)) where f (SpenderKey op) s = (fromIntegral (outPointIndex op), s) f _ _ = undefined getBalanceDB :: MonadIO m => Address -> BlockDB -> m (Maybe Balance) getBalanceDB a BlockDB {blockDBopts = opts, blockDB = db} = fmap (balValToBalance a) <$> retrieve db opts (BalKey a) getMempoolDB :: MonadIO m => BlockDB -> m [(UnixTime, TxHash)] getMempoolDB BlockDB {blockDBopts = opts, blockDB = db} = fromMaybe [] <$> retrieve db opts MemKey getOrphansDB :: (MonadIO m, MonadResource m) => BlockDB -> ConduitT i (UnixTime, Tx) m () getOrphansDB BlockDB {blockDBopts = opts, blockDB = db} = matching db opts OrphanKeyS .| mapC snd getOrphanTxDB :: MonadIO m => TxHash -> BlockDB -> m (Maybe (UnixTime, Tx)) getOrphanTxDB h BlockDB {blockDBopts = opts, blockDB = db} = retrieve db opts (OrphanKey h) getAddressTxsDB :: (MonadIO m, MonadResource m) => Address -> Maybe BlockRef -> BlockDB -> ConduitT i BlockTx m () getAddressTxsDB a mbr BlockDB {blockDBopts = opts, blockDB = db} = x .| mapC (uncurry f) where x = case mbr of Nothing -> matching db opts (AddrTxKeyA a) Just br -> matchingSkip db opts (AddrTxKeyA a) (AddrTxKeyB a br) f AddrTxKey {addrTxKeyT = t} () = t f _ _ = undefined getAddressBalancesDB :: (MonadIO m, MonadResource m) => BlockDB -> ConduitT i Balance m () getAddressBalancesDB BlockDB {blockDBopts = opts, blockDB = db} = matching db opts BalKeyS .| mapC (\(BalKey a, b) -> balValToBalance a b) getUnspentsDB :: (MonadIO m, MonadResource m) => BlockDB -> ConduitT i Unspent m () getUnspentsDB BlockDB {blockDBopts = opts, blockDB = db} = matching db opts UnspentKeyB .| mapC (\(UnspentKey k, v) -> unspentFromDB k v) getUnspentDB :: MonadIO m => OutPoint -> BlockDB -> m (Maybe Unspent) getUnspentDB p BlockDB {blockDBopts = opts, blockDB = db} = fmap (unspentValToUnspent p) <$> retrieve db opts (UnspentKey p) getAddressUnspentsDB :: (MonadIO m, MonadResource m) => Address -> Maybe BlockRef -> BlockDB -> ConduitT i Unspent m () getAddressUnspentsDB a mbr BlockDB {blockDBopts = opts, blockDB = db} = x .| mapC (uncurry f) where x = case mbr of Nothing -> matching db opts (AddrOutKeyA a) Just br -> matchingSkip db opts (AddrOutKeyA a) (AddrOutKeyB a br) f AddrOutKey {addrOutKeyB = b, addrOutKeyP = p} OutVal { outValAmount = v , outValScript = s } = Unspent { unspentBlock = b , unspentAmount = v , unspentScript = B.Short.toShort s , unspentPoint = p } f _ _ = undefined unspentFromDB :: OutPoint -> UnspentVal -> Unspent unspentFromDB p UnspentVal { unspentValBlock = b , unspentValAmount = v , unspentValScript = s } = Unspent { unspentBlock = b , unspentAmount = v , unspentPoint = p , unspentScript = s }