{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Haskoin.Store.Database.Reader
  ( -- * RocksDB Database Access
    DatabaseReader (..),
    DatabaseReaderT,
    withDatabaseReader,
    addrTxCF,
    addrOutCF,
    txCF,
    unspentCF,
    blockCF,
    heightCF,
    balanceCF,
  )
where

import Conduit
  ( ConduitT,
    dropC,
    dropWhileC,
    lift,
    mapC,
    runConduit,
    sinkList,
    takeC,
    (.|),
  )
import Control.Monad.Except (runExceptT, throwError)
import Control.Monad.Reader (ReaderT, ask, asks, runReaderT)
import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)
import Data.Bits ((.&.))
import qualified Data.ByteString as BS
import Data.Default (def)
import Data.Function (on)
import qualified Data.IntMap.Strict as IntMap
import Data.List (sortOn)
import Data.Maybe (fromMaybe)
import Data.Ord (Down (..))
import Data.Serialize (encode)
import Data.Word (Word32, Word64)
import Database.RocksDB
  ( ColumnFamily,
    Config (..),
    DB (..),
    Iterator,
    withDBCF,
    withIterCF,
  )
import Database.RocksDB.Query
  ( insert,
    matching,
    matchingAsListCF,
    matchingSkip,
    retrieve,
    retrieveCF,
  )
import Haskoin
  ( Address,
    BlockHash,
    BlockHeight,
    Network,
    OutPoint (..),
    TxHash,
    pubSubKey,
    txHash,
  )
import Haskoin.Store.Common
import Haskoin.Store.Data
import Haskoin.Store.Database.Types
import qualified System.Metrics as Metrics
import System.Metrics.Counter (Counter)
import qualified System.Metrics.Counter as Counter
import UnliftIO (MonadIO, MonadUnliftIO, liftIO)

type DatabaseReaderT = ReaderT DatabaseReader

data DatabaseReader = DatabaseReader
  { DatabaseReader -> DB
databaseHandle :: !DB,
    DatabaseReader -> Word32
databaseMaxGap :: !Word32,
    DatabaseReader -> Word32
databaseInitialGap :: !Word32,
    DatabaseReader -> Network
databaseNetwork :: !Network,
    DatabaseReader -> Maybe DataMetrics
databaseMetrics :: !(Maybe DataMetrics)
  }

incrementCounter ::
  MonadIO m =>
  (DataMetrics -> Counter) ->
  Int ->
  ReaderT DatabaseReader m ()
incrementCounter :: forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
f Int
i =
  forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> Maybe DataMetrics
databaseMetrics forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Just DataMetrics
s -> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Counter -> Int64 -> IO ()
Counter.add (DataMetrics -> Counter
f DataMetrics
s) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i)
    Maybe DataMetrics
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()

dataVersion :: Word32
dataVersion :: Word32
dataVersion = Word32
18

withDatabaseReader ::
  MonadUnliftIO m =>
  Network ->
  Word32 ->
  Word32 ->
  FilePath ->
  Maybe DataMetrics ->
  DatabaseReaderT m a ->
  m a
withDatabaseReader :: forall (m :: * -> *) a.
MonadUnliftIO m =>
Network
-> Word32
-> Word32
-> FilePath
-> Maybe DataMetrics
-> DatabaseReaderT m a
-> m a
withDatabaseReader Network
net Word32
igap Word32
gap FilePath
dir Maybe DataMetrics
stats DatabaseReaderT m a
f =
  forall (m :: * -> *) a.
MonadUnliftIO m =>
FilePath -> Config -> [(FilePath, Config)] -> (DB -> m a) -> m a
withDBCF FilePath
dir Config
cfg [(FilePath, Config)]
columnFamilyConfig forall a b. (a -> b) -> a -> b
$ \DB
db -> do
    let bdb :: DatabaseReader
bdb =
          DatabaseReader
            { databaseHandle :: DB
databaseHandle = DB
db,
              databaseMaxGap :: Word32
databaseMaxGap = Word32
gap,
              databaseNetwork :: Network
databaseNetwork = Network
net,
              databaseInitialGap :: Word32
databaseInitialGap = Word32
igap,
              databaseMetrics :: Maybe DataMetrics
databaseMetrics = Maybe DataMetrics
stats
            }
    forall (m :: * -> *). MonadIO m => DatabaseReader -> m ()
initRocksDB DatabaseReader
bdb
    forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT DatabaseReaderT m a
f DatabaseReader
bdb
  where
    cfg :: Config
cfg = forall a. Default a => a
def {createIfMissing :: Bool
createIfMissing = Bool
True, maxFiles :: Maybe Int
maxFiles = forall a. a -> Maybe a
Just (-Int
1)}

columnFamilyConfig :: [(String, Config)]
columnFamilyConfig :: [(FilePath, Config)]
columnFamilyConfig =
  [ (FilePath
"addr-tx", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
22, bloomFilter :: Bool
bloomFilter = Bool
True}),
    (FilePath
"addr-out", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
22, bloomFilter :: Bool
bloomFilter = Bool
True}),
    (FilePath
"tx", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
33, bloomFilter :: Bool
bloomFilter = Bool
True}),
    (FilePath
"spender", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
33, bloomFilter :: Bool
bloomFilter = Bool
True}), -- unused
    (FilePath
"unspent", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
37, bloomFilter :: Bool
bloomFilter = Bool
True}),
    (FilePath
"block", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
33, bloomFilter :: Bool
bloomFilter = Bool
True}),
    (FilePath
"height", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. Maybe a
Nothing, bloomFilter :: Bool
bloomFilter = Bool
True}),
    (FilePath
"balance", forall a. Default a => a
def {prefixLength :: Maybe Int
prefixLength = forall a. a -> Maybe a
Just Int
22, bloomFilter :: Bool
bloomFilter = Bool
True})
  ]

addrTxCF :: DB -> ColumnFamily
addrTxCF :: DB -> ColumnFamily
addrTxCF = forall a. [a] -> a
head forall b c a. (b -> c) -> (a -> b) -> a -> c
. DB -> [ColumnFamily]
columnFamilies

addrOutCF :: DB -> ColumnFamily
addrOutCF :: DB -> ColumnFamily
addrOutCF DB
db = DB -> [ColumnFamily]
columnFamilies DB
db forall a. [a] -> Int -> a
!! Int
1

txCF :: DB -> ColumnFamily
txCF :: DB -> ColumnFamily
txCF DB
db = DB -> [ColumnFamily]
columnFamilies DB
db forall a. [a] -> Int -> a
!! Int
2

unspentCF :: DB -> ColumnFamily
unspentCF :: DB -> ColumnFamily
unspentCF DB
db = DB -> [ColumnFamily]
columnFamilies DB
db forall a. [a] -> Int -> a
!! Int
4

blockCF :: DB -> ColumnFamily
blockCF :: DB -> ColumnFamily
blockCF DB
db = DB -> [ColumnFamily]
columnFamilies DB
db forall a. [a] -> Int -> a
!! Int
5

heightCF :: DB -> ColumnFamily
heightCF :: DB -> ColumnFamily
heightCF DB
db = DB -> [ColumnFamily]
columnFamilies DB
db forall a. [a] -> Int -> a
!! Int
6

balanceCF :: DB -> ColumnFamily
balanceCF :: DB -> ColumnFamily
balanceCF DB
db = DB -> [ColumnFamily]
columnFamilies DB
db forall a. [a] -> Int -> a
!! Int
7

initRocksDB :: MonadIO m => DatabaseReader -> m ()
initRocksDB :: forall (m :: * -> *). MonadIO m => DatabaseReader -> m ()
initRocksDB DatabaseReader {databaseHandle :: DatabaseReader -> DB
databaseHandle = DB
db} = do
  Either FilePath ()
e <-
    forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall a b. (a -> b) -> a -> b
$
      forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> key -> m (Maybe value)
retrieve DB
db VersionKey
VersionKey forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Just Word32
v
          | Word32
v forall a. Eq a => a -> a -> Bool
== Word32
dataVersion -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
          | Bool
otherwise -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError FilePath
"Incorrect RocksDB database version"
        Maybe Word32
Nothing -> forall (m :: * -> *). MonadIO m => DB -> m ()
setInitRocksDB DB
db
  case Either FilePath ()
e of
    Left FilePath
s -> forall a. HasCallStack => FilePath -> a
error FilePath
s
    Right () -> forall (m :: * -> *) a. Monad m => a -> m a
return ()

setInitRocksDB :: MonadIO m => DB -> m ()
setInitRocksDB :: forall (m :: * -> *). MonadIO m => DB -> m ()
setInitRocksDB DB
db = forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> key -> value -> m ()
insert DB
db VersionKey
VersionKey Word32
dataVersion

addressConduit ::
  MonadUnliftIO m =>
  Address ->
  Maybe Start ->
  Iterator ->
  ConduitT i TxRef (DatabaseReaderT m) ()
addressConduit :: forall (m :: * -> *) i.
MonadUnliftIO m =>
Address
-> Maybe Start
-> Iterator
-> ConduitT i TxRef (DatabaseReaderT m) ()
addressConduit Address
a Maybe Start
s Iterator
it =
  forall {i}. ConduitT i (AddrTxKey, ()) (DatabaseReaderT m) ()
x forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) a b. Monad m => (a -> b) -> ConduitT a b m ()
mapC (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry AddrTxKey -> () -> TxRef
f)
  where
    f :: AddrTxKey -> () -> TxRef
f (AddrTxKey Address
_ TxRef
t) () = TxRef
t
    f AddrTxKey
_ ()
_ = forall a. HasCallStack => a
undefined
    x :: ConduitT i (AddrTxKey, ()) (DatabaseReaderT m) ()
x = case Maybe Start
s of
      Maybe Start
Nothing ->
        forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> ConduitT i (key, value) m ()
matching Iterator
it (Address -> AddrTxKey
AddrTxKeyA Address
a)
      Just (AtBlock Word32
bh) ->
        forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> key -> ConduitT i (key, value) m ()
matchingSkip
          Iterator
it
          (Address -> AddrTxKey
AddrTxKeyA Address
a)
          (Address -> BlockRef -> AddrTxKey
AddrTxKeyB Address
a (Word32 -> Word32 -> BlockRef
BlockRef Word32
bh forall a. Bounded a => a
maxBound))
      Just (AtTx TxHash
txh) ->
        forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *). StoreReadBase m => TxHash -> m (Maybe TxData)
getTxData TxHash
txh) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
          Just TxData {txDataBlock :: TxData -> BlockRef
txDataBlock = b :: BlockRef
b@BlockRef {}} ->
            forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> key -> ConduitT i (key, value) m ()
matchingSkip Iterator
it (Address -> AddrTxKey
AddrTxKeyA Address
a) (Address -> BlockRef -> AddrTxKey
AddrTxKeyB Address
a BlockRef
b)
          Just TxData {txDataBlock :: TxData -> BlockRef
txDataBlock = MemRef {}} ->
            let cond :: AddrTxKey -> Bool
cond (AddrTxKey Address
_a (TxRef MemRef {} TxHash
th)) =
                  TxHash
th forall a. Eq a => a -> a -> Bool
/= TxHash
txh
                cond (AddrTxKey Address
_a (TxRef BlockRef {} TxHash
_th)) =
                  Bool
False
             in forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> ConduitT i (key, value) m ()
matching Iterator
it (Address -> AddrTxKey
AddrTxKeyA Address
a)
                  forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| (forall (m :: * -> *) a o.
Monad m =>
(a -> Bool) -> ConduitT a o m ()
dropWhileC (AddrTxKey -> Bool
cond forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a b. Monad m => (a -> b) -> ConduitT a b m ()
mapC forall a. a -> a
id)
          Maybe TxData
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()

unspentConduit ::
  MonadUnliftIO m =>
  Address ->
  Maybe Start ->
  Iterator ->
  ConduitT i Unspent (DatabaseReaderT m) ()
unspentConduit :: forall (m :: * -> *) i.
MonadUnliftIO m =>
Address
-> Maybe Start
-> Iterator
-> ConduitT i Unspent (DatabaseReaderT m) ()
unspentConduit Address
a Maybe Start
s Iterator
it =
  forall {i}. ConduitT i (AddrOutKey, OutVal) (DatabaseReaderT m) ()
x forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) a b. Monad m => (a -> b) -> ConduitT a b m ()
mapC (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry AddrOutKey -> OutVal -> Unspent
toUnspent)
  where
    x :: ConduitT i (AddrOutKey, OutVal) (DatabaseReaderT m) ()
x = case Maybe Start
s of
      Maybe Start
Nothing ->
        forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> ConduitT i (key, value) m ()
matching Iterator
it (Address -> AddrOutKey
AddrOutKeyA Address
a)
      Just (AtBlock Word32
h) ->
        forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> key -> ConduitT i (key, value) m ()
matchingSkip
          Iterator
it
          (Address -> AddrOutKey
AddrOutKeyA Address
a)
          (Address -> BlockRef -> AddrOutKey
AddrOutKeyB Address
a (Word32 -> Word32 -> BlockRef
BlockRef Word32
h forall a. Bounded a => a
maxBound))
      Just (AtTx TxHash
txh) ->
        forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (forall (m :: * -> *). StoreReadBase m => TxHash -> m (Maybe TxData)
getTxData TxHash
txh) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
          Just TxData {txDataBlock :: TxData -> BlockRef
txDataBlock = b :: BlockRef
b@BlockRef {}} ->
            forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> key -> ConduitT i (key, value) m ()
matchingSkip Iterator
it (Address -> AddrOutKey
AddrOutKeyA Address
a) (Address -> BlockRef -> AddrOutKey
AddrOutKeyB Address
a BlockRef
b)
          Just TxData {txDataBlock :: TxData -> BlockRef
txDataBlock = MemRef {}} ->
            let cond :: AddrOutKey -> Bool
cond (AddrOutKey Address
_a MemRef {} OutPoint
p) =
                  OutPoint -> TxHash
outPointHash OutPoint
p forall a. Eq a => a -> a -> Bool
/= TxHash
txh
                cond (AddrOutKey Address
_a BlockRef {} OutPoint
_p) =
                  Bool
False
             in forall (m :: * -> *) key value i.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
Iterator -> key -> ConduitT i (key, value) m ()
matching Iterator
it (Address -> AddrOutKey
AddrOutKeyA Address
a)
                  forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| (forall (m :: * -> *) a o.
Monad m =>
(a -> Bool) -> ConduitT a o m ()
dropWhileC (AddrOutKey -> Bool
cond forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a b. Monad m => (a -> b) -> ConduitT a b m ()
mapC forall a. a -> a
id)
          Maybe TxData
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()

withManyIters ::
  MonadUnliftIO m =>
  DB ->
  ColumnFamily ->
  Int ->
  ([Iterator] -> m a) ->
  m a
withManyIters :: forall (m :: * -> *) a.
MonadUnliftIO m =>
DB -> ColumnFamily -> Int -> ([Iterator] -> m a) -> m a
withManyIters DB
db ColumnFamily
cf Int
i [Iterator] -> m a
f = forall {t}. (Eq t, Num t) => [Iterator] -> t -> m a
go [] Int
i
  where
    go :: [Iterator] -> t -> m a
go [Iterator]
acc t
0 = [Iterator] -> m a
f [Iterator]
acc
    go [Iterator]
acc t
n = forall (m :: * -> *) a.
MonadUnliftIO m =>
DB -> ColumnFamily -> (Iterator -> m a) -> m a
withIterCF DB
db ColumnFamily
cf forall a b. (a -> b) -> a -> b
$ \Iterator
it -> [Iterator] -> t -> m a
go (Iterator
it forall a. a -> [a] -> [a]
: [Iterator]
acc) (t
n forall a. Num a => a -> a -> a
- t
1)

joinConduits ::
  (Monad m, Ord o) =>
  [ConduitT () o m ()] ->
  Limits ->
  m [o]
joinConduits :: forall (m :: * -> *) o.
(Monad m, Ord o) =>
[ConduitT () o m ()] -> Limits -> m [o]
joinConduits [ConduitT () o m ()]
cs Limits
l =
  forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
(Monad m, Ord a) =>
[ConduitT () a m ()] -> ConduitT () a m ()
joinDescStreams [ConduitT () o m ()]
cs forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) i. Monad m => Limits -> ConduitT i i m ()
applyLimitsC Limits
l forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) a o. Monad m => ConduitT a o m [a]
sinkList

instance MonadIO m => StoreReadBase (DatabaseReaderT m) where
  getNetwork :: DatabaseReaderT m Network
getNetwork = forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> Network
databaseNetwork

  getTxData :: TxHash -> DatabaseReaderT m (Maybe TxData)
getTxData TxHash
th = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> ColumnFamily -> key -> m (Maybe value)
retrieveCF DB
db (DB -> ColumnFamily
txCF DB
db) (TxHash -> TxKey
TxKey TxHash
th) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Maybe TxData
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
      Just TxData
t -> do
        forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataTxCount Int
1
        forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just TxData
t)

  getSpender :: OutPoint -> DatabaseReaderT m (Maybe Spender)
getSpender OutPoint
op = forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT forall a b. (a -> b) -> a -> b
$ do
    TxData
td <- forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *). StoreReadBase m => TxHash -> m (Maybe TxData)
getTxData (OutPoint -> TxHash
outPointHash OutPoint
op)
    let i :: Int
i = forall a b. (Integral a, Num b) => a -> b
fromIntegral (OutPoint -> Word32
outPointIndex OutPoint
op)
    forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int
i forall a. Int -> IntMap a -> Maybe a
`IntMap.lookup` TxData -> IntMap Spender
txDataSpenders TxData
td

  getUnspent :: OutPoint -> DatabaseReaderT m (Maybe Unspent)
getUnspent OutPoint
p = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    Maybe UnspentVal
val <- forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> ColumnFamily -> key -> m (Maybe value)
retrieveCF DB
db (DB -> ColumnFamily
unspentCF DB
db) (OutPoint -> UnspentKey
UnspentKey OutPoint
p)
    case forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (OutPoint -> UnspentVal -> Unspent
valToUnspent OutPoint
p) Maybe UnspentVal
val of
      Maybe Unspent
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
      Just Unspent
u -> do
        forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataUnspentCount Int
1
        forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just Unspent
u)

  getBalance :: Address -> DatabaseReaderT m (Maybe Balance)
getBalance Address
a = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataBalanceCount Int
1
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Address -> BalVal -> Balance
valToBalance Address
a) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> ColumnFamily -> key -> m (Maybe value)
retrieveCF DB
db (DB -> ColumnFamily
balanceCF DB
db) (Address -> BalKey
BalKey Address
a)

  getMempool :: DatabaseReaderT m [(UnixTime, TxHash)]
getMempool = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataMempoolCount Int
1
    forall a. a -> Maybe a -> a
fromMaybe [] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> key -> m (Maybe value)
retrieve DB
db MemKey
MemKey

  getBestBlock :: DatabaseReaderT m (Maybe BlockHash)
getBestBlock = do
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataBestCount Int
1
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> key -> m (Maybe value)
`retrieve` BestKey
BestKey)

  getBlocksAtHeight :: Word32 -> DatabaseReaderT m [BlockHash]
getBlocksAtHeight Word32
h = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> ColumnFamily -> key -> m (Maybe value)
retrieveCF DB
db (DB -> ColumnFamily
heightCF DB
db) (Word32 -> HeightKey
HeightKey Word32
h) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Maybe [BlockHash]
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return []
      Just [BlockHash]
ls -> do
        forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataBlockCount (forall (t :: * -> *) a. Foldable t => t a -> Int
length [BlockHash]
ls)
        forall (m :: * -> *) a. Monad m => a -> m a
return [BlockHash]
ls

  getBlock :: BlockHash -> DatabaseReaderT m (Maybe BlockData)
getBlock BlockHash
h = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *) key value.
(MonadIO m, KeyValue key value, Serialize key, Serialize value) =>
DB -> ColumnFamily -> key -> m (Maybe value)
retrieveCF DB
db (DB -> ColumnFamily
blockCF DB
db) (BlockHash -> BlockKey
BlockKey BlockHash
h) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      Maybe BlockData
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
      Just BlockData
b -> do
        forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataBlockCount Int
1
        forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just BlockData
b)

instance MonadUnliftIO m => StoreReadExtra (DatabaseReaderT m) where
  getAddressesTxs :: [Address] -> Limits -> DatabaseReaderT m [TxRef]
getAddressesTxs [Address]
addrs Limits
limits = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *) a.
MonadUnliftIO m =>
DB -> ColumnFamily -> Int -> ([Iterator] -> m a) -> m a
withManyIters DB
db (DB -> ColumnFamily
addrTxCF DB
db) (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Address]
addrs) forall a b. (a -> b) -> a -> b
$ \[Iterator]
its -> do
      [TxRef]
txs <- forall (m :: * -> *) o.
(Monad m, Ord o) =>
[ConduitT () o m ()] -> Limits -> m [o]
joinConduits (forall {i}. [Iterator] -> [ConduitT i TxRef (DatabaseReaderT m) ()]
cs [Iterator]
its) Limits
limits
      forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataAddrTxCount (forall (t :: * -> *) a. Foldable t => t a -> Int
length [TxRef]
txs)
      forall (m :: * -> *) a. Monad m => a -> m a
return [TxRef]
txs
    where
      cs :: [Iterator] -> [ConduitT i TxRef (DatabaseReaderT m) ()]
cs = forall a b. (a -> b) -> [a] -> [b]
map (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall {m :: * -> *} {i}.
MonadUnliftIO m =>
Address -> Iterator -> ConduitT i TxRef (DatabaseReaderT m) ()
c) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. [a] -> [b] -> [(a, b)]
zip [Address]
addrs
      c :: Address -> Iterator -> ConduitT i TxRef (DatabaseReaderT m) ()
c Address
a = forall (m :: * -> *) i.
MonadUnliftIO m =>
Address
-> Maybe Start
-> Iterator
-> ConduitT i TxRef (DatabaseReaderT m) ()
addressConduit Address
a (Limits -> Maybe Start
start Limits
limits)

  getAddressesUnspents :: [Address] -> Limits -> DatabaseReaderT m [Unspent]
getAddressesUnspents [Address]
addrs Limits
limits = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    forall (m :: * -> *) a.
MonadUnliftIO m =>
DB -> ColumnFamily -> Int -> ([Iterator] -> m a) -> m a
withManyIters DB
db (DB -> ColumnFamily
addrOutCF DB
db) (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Address]
addrs) forall a b. (a -> b) -> a -> b
$ \[Iterator]
its -> do
      [Unspent]
uns <- forall (m :: * -> *) o.
(Monad m, Ord o) =>
[ConduitT () o m ()] -> Limits -> m [o]
joinConduits (forall {i}.
[Iterator] -> [ConduitT i Unspent (DatabaseReaderT m) ()]
cs [Iterator]
its) Limits
limits
      forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataUnspentCount (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Unspent]
uns)
      forall (m :: * -> *) a. Monad m => a -> m a
return [Unspent]
uns
    where
      cs :: [Iterator] -> [ConduitT i Unspent (DatabaseReaderT m) ()]
cs = forall a b. (a -> b) -> [a] -> [b]
map (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry forall {m :: * -> *} {i}.
MonadUnliftIO m =>
Address -> Iterator -> ConduitT i Unspent (DatabaseReaderT m) ()
c) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. [a] -> [b] -> [(a, b)]
zip [Address]
addrs
      c :: Address -> Iterator -> ConduitT i Unspent (DatabaseReaderT m) ()
c Address
a = forall (m :: * -> *) i.
MonadUnliftIO m =>
Address
-> Maybe Start
-> Iterator
-> ConduitT i Unspent (DatabaseReaderT m) ()
unspentConduit Address
a (Limits -> Maybe Start
start Limits
limits)

  getAddressUnspents :: Address -> Limits -> DatabaseReaderT m [Unspent]
getAddressUnspents Address
a Limits
limits = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    [Unspent]
us <- forall (m :: * -> *) a.
MonadUnliftIO m =>
DB -> ColumnFamily -> (Iterator -> m a) -> m a
withIterCF DB
db (DB -> ColumnFamily
addrOutCF DB
db) forall a b. (a -> b) -> a -> b
$ \Iterator
it ->
      forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit forall a b. (a -> b) -> a -> b
$
        forall (m :: * -> *) i.
MonadUnliftIO m =>
Address
-> Maybe Start
-> Iterator
-> ConduitT i Unspent (DatabaseReaderT m) ()
unspentConduit Address
a (Limits -> Maybe Start
start Limits
limits) Iterator
it
          forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) i. Monad m => Limits -> ConduitT i i m ()
applyLimitsC Limits
limits
          forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) a o. Monad m => ConduitT a o m [a]
sinkList
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataUnspentCount (forall (t :: * -> *) a. Foldable t => t a -> Int
length [Unspent]
us)
    forall (m :: * -> *) a. Monad m => a -> m a
return [Unspent]
us

  getAddressTxs :: Address -> Limits -> DatabaseReaderT m [TxRef]
getAddressTxs Address
a Limits
limits = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    [TxRef]
txs <- forall (m :: * -> *) a.
MonadUnliftIO m =>
DB -> ColumnFamily -> (Iterator -> m a) -> m a
withIterCF DB
db (DB -> ColumnFamily
addrTxCF DB
db) forall a b. (a -> b) -> a -> b
$ \Iterator
it ->
      forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit forall a b. (a -> b) -> a -> b
$
        forall (m :: * -> *) i.
MonadUnliftIO m =>
Address
-> Maybe Start
-> Iterator
-> ConduitT i TxRef (DatabaseReaderT m) ()
addressConduit Address
a (Limits -> Maybe Start
start Limits
limits) Iterator
it
          forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) i. Monad m => Limits -> ConduitT i i m ()
applyLimitsC Limits
limits
          forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| forall (m :: * -> *) a o. Monad m => ConduitT a o m [a]
sinkList
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataAddrTxCount (forall (t :: * -> *) a. Foldable t => t a -> Int
length [TxRef]
txs)
    forall (m :: * -> *) a. Monad m => a -> m a
return [TxRef]
txs

  getMaxGap :: DatabaseReaderT m Word32
getMaxGap = forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> Word32
databaseMaxGap

  getInitialGap :: DatabaseReaderT m Word32
getInitialGap = forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> Word32
databaseInitialGap

  getNumTxData :: UnixTime -> DatabaseReaderT m [TxData]
getNumTxData UnixTime
i = do
    DB
db <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DatabaseReader -> DB
databaseHandle
    let ((Word32, Word16)
sk, Word8
w) = UnixTime -> ((Word32, Word16), Word8)
decodeTxKey UnixTime
i
    [(TxKey, TxData)]
ls <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) key value.
(MonadUnliftIO m, KeyValue key value, Serialize key,
 Serialize value) =>
DB -> ColumnFamily -> key -> m [(key, value)]
matchingAsListCF DB
db (DB -> ColumnFamily
txCF DB
db) ((Word32, Word16) -> TxKey
TxKeyS (Word32, Word16)
sk)
    let f :: TxData -> Bool
f TxData
t =
          let bs :: ByteString
bs = forall a. Serialize a => a -> ByteString
encode forall a b. (a -> b) -> a -> b
$ Tx -> TxHash
txHash (TxData -> Tx
txData TxData
t)
              b :: Word8
b = HasCallStack => ByteString -> Word8
BS.head (Int -> ByteString -> ByteString
BS.drop Int
6 ByteString
bs)
              w' :: Word8
w' = Word8
b forall a. Bits a => a -> a -> a
.&. Word8
0xf8
           in Word8
w forall a. Eq a => a -> a -> Bool
== Word8
w'
        txs :: [TxData]
txs = forall a. (a -> Bool) -> [a] -> [a]
filter TxData -> Bool
f forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [(TxKey, TxData)]
ls
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataTxCount (forall (t :: * -> *) a. Foldable t => t a -> Int
length [TxData]
txs)
    forall (m :: * -> *) a. Monad m => a -> m a
return [TxData]
txs

  getBalances :: [Address] -> DatabaseReaderT m [Balance]
getBalances [Address]
as = do
    forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Address -> Maybe Balance -> Balance
f [Address]
as forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall (m :: * -> *).
StoreReadBase m =>
Address -> m (Maybe Balance)
getBalance [Address]
as
    where
      f :: Address -> Maybe Balance -> Balance
f Address
a Maybe Balance
Nothing = Address -> Balance
zeroBalance Address
a
      f Address
_ (Just Balance
b) = Balance
b

  xPubBals :: XPubSpec -> DatabaseReaderT m [XPubBal]
xPubBals XPubSpec
xpub = do
    Word32
igap <- forall (m :: * -> *). StoreReadExtra m => m Word32
getInitialGap
    Word32
gap <- forall (m :: * -> *). StoreReadExtra m => m Word32
getMaxGap
    [XPubBal]
ext1 <- forall {m :: * -> *} {t}.
(StoreReadExtra m, Integral t) =>
t -> Word32 -> [(Word32, Address)] -> m [XPubBal]
derive_until_gap Word32
gap Word32
0 (forall a. Int -> [a] -> [a]
take (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
igap) (Word32 -> Word32 -> [(Word32, Address)]
aderiv Word32
0 Word32
0))
    if forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Balance -> Bool
nullBalance forall b c a. (b -> c) -> (a -> b) -> a -> c
. XPubBal -> Balance
xPubBal) [XPubBal]
ext1
      then do
        forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataXPubBals (forall (t :: * -> *) a. Foldable t => t a -> Int
length [XPubBal]
ext1)
        forall (m :: * -> *) a. Monad m => a -> m a
return [XPubBal]
ext1
      else do
        [XPubBal]
ext2 <- forall {m :: * -> *} {t}.
(StoreReadExtra m, Integral t) =>
t -> Word32 -> [(Word32, Address)] -> m [XPubBal]
derive_until_gap Word32
gap Word32
0 (Word32 -> Word32 -> [(Word32, Address)]
aderiv Word32
0 Word32
igap)
        [XPubBal]
chg <- forall {m :: * -> *} {t}.
(StoreReadExtra m, Integral t) =>
t -> Word32 -> [(Word32, Address)] -> m [XPubBal]
derive_until_gap Word32
gap Word32
1 (Word32 -> Word32 -> [(Word32, Address)]
aderiv Word32
1 Word32
0)
        let bals :: [XPubBal]
bals = [XPubBal]
ext1 forall a. Semigroup a => a -> a -> a
<> [XPubBal]
ext2 forall a. Semigroup a => a -> a -> a
<> [XPubBal]
chg
        forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataXPubBals (forall (t :: * -> *) a. Foldable t => t a -> Int
length [XPubBal]
bals)
        forall (m :: * -> *) a. Monad m => a -> m a
return [XPubBal]
bals
    where
      aderiv :: Word32 -> Word32 -> [(Word32, Address)]
aderiv Word32
m =
        DeriveAddr -> XPubKey -> Word32 -> [(Word32, Address)]
deriveAddresses
          (DeriveType -> DeriveAddr
deriveFunction (XPubSpec -> DeriveType
xPubDeriveType XPubSpec
xpub))
          (XPubKey -> Word32 -> XPubKey
pubSubKey (XPubSpec -> XPubKey
xPubSpecKey XPubSpec
xpub) Word32
m)
      xbalance :: Word32 -> Balance -> Word32 -> XPubBal
xbalance Word32
m Balance
b Word32
n = XPubBal {xPubBalPath :: [Word32]
xPubBalPath = [Word32
m, Word32
n], xPubBal :: Balance
xPubBal = Balance
b}
      derive_until_gap :: t -> Word32 -> [(Word32, Address)] -> m [XPubBal]
derive_until_gap t
_ Word32
_ [] = forall (m :: * -> *) a. Monad m => a -> m a
return []
      derive_until_gap t
gap Word32
m [(Word32, Address)]
as = do
        let ([(Word32, Address)]
as1, [(Word32, Address)]
as2) = forall a. Int -> [a] -> ([a], [a])
splitAt (forall a b. (Integral a, Num b) => a -> b
fromIntegral t
gap) [(Word32, Address)]
as
        [Balance]
bs <- forall (m :: * -> *). StoreReadExtra m => [Address] -> m [Balance]
getBalances (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [(Word32, Address)]
as1)
        let xbs :: [XPubBal]
xbs = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (Word32 -> Balance -> Word32 -> XPubBal
xbalance Word32
m) [Balance]
bs (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst [(Word32, Address)]
as1)
        if forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Balance -> Bool
nullBalance [Balance]
bs
          then forall (m :: * -> *) a. Monad m => a -> m a
return [XPubBal]
xbs
          else ([XPubBal]
xbs forall a. Semigroup a => a -> a -> a
<>) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> t -> Word32 -> [(Word32, Address)] -> m [XPubBal]
derive_until_gap t
gap Word32
m [(Word32, Address)]
as2

  xPubUnspents :: XPubSpec -> [XPubBal] -> Limits -> DatabaseReaderT m [XPubUnspent]
xPubUnspents XPubSpec
_xspec [XPubBal]
xbals Limits
limits = do
    [XPubUnspent]
us <- forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall {f :: * -> *}.
StoreReadExtra f =>
XPubBal -> f [XPubUnspent]
h [XPubBal]
cs
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataXPubUnspents (forall (t :: * -> *) a. Foldable t => t a -> Int
length [XPubUnspent]
us)
    forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Limits -> [a] -> [a]
applyLimits Limits
limits forall a b. (a -> b) -> a -> b
$ forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn forall a. a -> Down a
Down [XPubUnspent]
us
    where
      l :: Limits
l = Limits -> Limits
deOffset Limits
limits
      cs :: [XPubBal]
cs = forall a. (a -> Bool) -> [a] -> [a]
filter ((forall a. Ord a => a -> a -> Bool
> UnixTime
0) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Balance -> UnixTime
balanceUnspentCount forall b c a. (b -> c) -> (a -> b) -> a -> c
. XPubBal -> Balance
xPubBal) [XPubBal]
xbals
      i :: XPubBal -> m [Unspent]
i XPubBal
b = do
        [Unspent]
us <- forall (m :: * -> *).
StoreReadExtra m =>
Address -> Limits -> m [Unspent]
getAddressUnspents (Balance -> Address
balanceAddress (XPubBal -> Balance
xPubBal XPubBal
b)) Limits
l
        forall (m :: * -> *) a. Monad m => a -> m a
return [Unspent]
us
      f :: XPubBal -> Unspent -> XPubUnspent
f XPubBal
b Unspent
t = XPubUnspent {xPubUnspentPath :: [Word32]
xPubUnspentPath = XPubBal -> [Word32]
xPubBalPath XPubBal
b, xPubUnspent :: Unspent
xPubUnspent = Unspent
t}
      h :: XPubBal -> f [XPubUnspent]
h XPubBal
b = forall a b. (a -> b) -> [a] -> [b]
map (XPubBal -> Unspent -> XPubUnspent
f XPubBal
b) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall {m :: * -> *}. StoreReadExtra m => XPubBal -> m [Unspent]
i XPubBal
b

  xPubTxs :: XPubSpec -> [XPubBal] -> Limits -> DatabaseReaderT m [TxRef]
xPubTxs XPubSpec
_xspec [XPubBal]
xbals Limits
limits = do
    let as :: [Address]
as =
          forall a b. (a -> b) -> [a] -> [b]
map Balance -> Address
balanceAddress forall a b. (a -> b) -> a -> b
$
            forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Balance -> Bool
nullBalance) forall a b. (a -> b) -> a -> b
$
              forall a b. (a -> b) -> [a] -> [b]
map XPubBal -> Balance
xPubBal [XPubBal]
xbals
    [TxRef]
txs <- forall (m :: * -> *).
StoreReadExtra m =>
[Address] -> Limits -> m [TxRef]
getAddressesTxs [Address]
as Limits
limits
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataXPubTxs (forall (t :: * -> *) a. Foldable t => t a -> Int
length [TxRef]
txs)
    forall (m :: * -> *) a. Monad m => a -> m a
return [TxRef]
txs

  xPubTxCount :: XPubSpec -> [XPubBal] -> DatabaseReaderT m Word32
xPubTxCount XPubSpec
xspec [XPubBal]
xbals = do
    forall (m :: * -> *).
MonadIO m =>
(DataMetrics -> Counter) -> Int -> ReaderT DatabaseReader m ()
incrementCounter DataMetrics -> Counter
dataXPubTxCount Int
1
    forall a b. (Integral a, Num b) => a -> b
fromIntegral forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Int
length forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *).
StoreReadExtra m =>
XPubSpec -> [XPubBal] -> Limits -> m [TxRef]
xPubTxs XPubSpec
xspec [XPubBal]
xbals forall a. Default a => a
def