diff --git a/haskoin-store.cabal b/haskoin-store.cabal
--- a/haskoin-store.cabal
+++ b/haskoin-store.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 697b02b2afcb3a3cf353fa248771abc9f0fb2e0d6fb0825e3fa37bced3622695
+-- hash: 32be1f4a3da179a635d98745d8b60cd57647439c7d934b319b38e5e3d370e336
 
 name:           haskoin-store
-version:        0.28.0
+version:        0.29.0
 synopsis:       Storage and index for Bitcoin and Bitcoin Cash
 description:    Store and index Bitcoin or Bitcoin Cash blocks, transactions, balances and unspent outputs.
                 All data is available via REST API in JSON or binary format.
@@ -57,7 +57,7 @@
     , hashable >=1.3.0.0
     , haskoin-core >=0.13.3
     , haskoin-node >=0.13.0
-    , haskoin-store-data ==0.28.0
+    , haskoin-store-data ==0.29.0
     , hedis >=0.12.13
     , http-types >=0.12.3
     , monad-logger >=0.3.32
@@ -99,7 +99,7 @@
     , haskoin-core >=0.13.3
     , haskoin-node >=0.13.0
     , haskoin-store
-    , haskoin-store-data ==0.28.0
+    , haskoin-store-data ==0.29.0
     , monad-logger >=0.3.32
     , mtl >=2.2.2
     , nqe >=0.6.1
@@ -149,7 +149,7 @@
     , hashable >=1.3.0.0
     , haskoin-core >=0.13.3
     , haskoin-node >=0.13.0
-    , haskoin-store-data ==0.28.0
+    , haskoin-store-data ==0.29.0
     , hedis >=0.12.13
     , hspec >=2.7.1
     , http-types >=0.12.3
diff --git a/src/Haskoin/Store/BlockStore.hs b/src/Haskoin/Store/BlockStore.hs
--- a/src/Haskoin/Store/BlockStore.hs
+++ b/src/Haskoin/Store/BlockStore.hs
@@ -30,8 +30,6 @@
 import           Control.Applicative           ((<|>))
 import           Control.Monad                 (forM, forM_, forever, mzero,
                                                 unless, void, when)
-import           Control.Monad.Except          (ExceptT, MonadError (..),
-                                                runExceptT)
 import           Control.Monad.Logger          (MonadLoggerIO, logDebugS,
                                                 logErrorS, logInfoS, logWarnS)
 import           Control.Monad.Reader          (MonadReader, ReaderT (..), asks)
@@ -70,13 +68,13 @@
                                                 managerPeerText)
 import           Haskoin.Store.Common          (StoreEvent (..), StoreRead (..),
                                                 sortTxs)
-import           Haskoin.Store.Data            (BlockTx (..), TxData (..),
+import           Haskoin.Store.Data            (TxData (..), TxRef (..),
                                                 UnixTime, Unspent (..))
 import           Haskoin.Store.Database.Reader (DatabaseReader)
 import           Haskoin.Store.Database.Writer (DatabaseWriter,
                                                 runDatabaseWriter)
 import           Haskoin.Store.Logic           (ImportException (TxOrphan),
-                                                deleteTx, getOldMempool,
+                                                delTx, getOldMempool,
                                                 importBlock, initBest,
                                                 newMempoolTx, revertBlock)
 import           Network.Socket                (SockAddr)
@@ -86,9 +84,10 @@
 import           System.Random                 (randomRIO)
 import           UnliftIO                      (Exception, MonadIO,
                                                 MonadUnliftIO, STM, TVar,
-                                                atomically, liftIO, modifyTVar,
-                                                newTVarIO, readTVar, readTVarIO,
-                                                throwIO, withAsync, writeTVar)
+                                                atomically, catch, liftIO,
+                                                modifyTVar, newTVarIO, readTVar,
+                                                readTVarIO, throwIO, try,
+                                                withAsync, writeTVar)
 import           UnliftIO.Concurrent           (threadDelay)
 
 -- | Messages for block store actor.
@@ -103,9 +102,9 @@
       -- ^ new block received from a peer
     | BlockNotFound !Peer ![BlockHash]
       -- ^ block not found
-    | BlockTxReceived !Peer !Tx
+    | TxRefReceived !Peer !Tx
       -- ^ transaction received from peer
-    | BlockTxAvailable !Peer ![TxHash]
+    | TxRefAvailable !Peer ![TxHash]
       -- ^ peer has transactions available
     | BlockPing !(Listen ())
       -- ^ internal housekeeping ping
@@ -166,11 +165,11 @@
 type BlockT m = ReaderT BlockRead m
 
 runImport ::
-       MonadLoggerIO m
-    => ReaderT DatabaseWriter (ExceptT ImportException m) a
+       (MonadLoggerIO m, MonadUnliftIO m)
+    => ReaderT DatabaseWriter m a
     -> ReaderT BlockRead m (Either ImportException a)
 runImport f =
-    ReaderT $ \r -> runExceptT (runDatabaseWriter (blockConfDB (myConfig r)) f)
+    ReaderT $ \r -> try (runDatabaseWriter (blockConfDB (myConfig r)) f)
 
 runRocksDB :: ReaderT DatabaseReader m a -> ReaderT BlockRead m a
 runRocksDB f =
@@ -218,8 +217,8 @@
             $(logDebugS) "BlockStore" $
                 "Wiping mempool tx " <> cs (show i) <> "/" <> cs (show n) <>
                 ": " <>
-                txHashToHex (blockTxHash tx)
-            deleteTx True False (blockTxHash tx)
+                txHashToHex (txRefHash tx)
+            delTx (txRefHash tx)
     wipeit x n txs = do
         let (txs1, txs2) = splitAt 1000 txs
         case txs1 of
@@ -463,7 +462,7 @@
                             case x of
                                 Just ls -> Right (th, ls)
                                 Nothing -> Left Nothing
-                catchError f (h p)
+                catch f (h p)
         case output of
             Left e -> do
                 $(logErrorS) "BlockStore" $
@@ -588,10 +587,11 @@
     deletetxs old = do
         forM_ (zip [(1 :: Int) ..] old) $ \(i, txid) -> do
             $(logInfoS) "BlockStore" $
-                "Removing " <> cs (show i) <> "/" <> cs (show (length old)) <>
-                " old mempool tx " <>
+                "Removing old mempool tx " <> cs (show i) <> "/" <>
+                cs (show (length old)) <>
+                ": " <>
                 txHashToHex txid
-            runImport (deleteTx True False txid) >>= \case
+            runImport (delTx txid) >>= \case
                 Left _ -> return ()
                 Right txids -> do
                     listener <- asks (blockConfListener . myConfig)
@@ -746,8 +746,8 @@
 processBlockStoreMessage (BlockPeerDisconnect p _sa) = processDisconnect p
 processBlockStoreMessage (BlockReceived p b) = processBlock p b
 processBlockStoreMessage (BlockNotFound p bs) = processNoBlocks p bs
-processBlockStoreMessage (BlockTxReceived p tx) = processTx p tx
-processBlockStoreMessage (BlockTxAvailable p ts) = processTxs p ts
+processBlockStoreMessage (TxRefReceived p tx) = processTx p tx
+processBlockStoreMessage (TxRefAvailable p ts) = processTxs p ts
 processBlockStoreMessage (BlockPing r) = do
     processMempool
     pruneOrphans
@@ -778,11 +778,11 @@
 blockStoreNotFound peer blocks store = BlockNotFound peer blocks `send` store
 
 blockStoreTx :: MonadIO m => Peer -> Tx -> BlockStore -> m ()
-blockStoreTx peer tx store = BlockTxReceived peer tx `send` store
+blockStoreTx peer tx store = TxRefReceived peer tx `send` store
 
 blockStoreTxHash :: MonadIO m => Peer -> [TxHash] -> BlockStore -> m ()
 blockStoreTxHash peer txhashes store =
-    BlockTxAvailable peer txhashes `send` store
+    TxRefAvailable peer txhashes `send` store
 
 blockStorePeerConnectSTM :: Peer -> SockAddr -> BlockStore -> STM ()
 blockStorePeerConnectSTM peer addr store = BlockPeerConnect peer addr `sendSTM` store
@@ -801,11 +801,11 @@
 blockStoreNotFoundSTM peer blocks store = BlockNotFound peer blocks `sendSTM` store
 
 blockStoreTxSTM :: Peer -> Tx -> BlockStore -> STM ()
-blockStoreTxSTM peer tx store = BlockTxReceived peer tx `sendSTM` store
+blockStoreTxSTM peer tx store = TxRefReceived peer tx `sendSTM` store
 
 blockStoreTxHashSTM :: Peer -> [TxHash] -> BlockStore -> STM ()
 blockStoreTxHashSTM peer txhashes store =
-    BlockTxAvailable peer txhashes `sendSTM` store
+    TxRefAvailable peer txhashes `sendSTM` store
 
 blockText :: BlockNode -> [Tx] -> Text
 blockText bn txs
diff --git a/src/Haskoin/Store/Cache.hs b/src/Haskoin/Store/Cache.hs
--- a/src/Haskoin/Store/Cache.hs
+++ b/src/Haskoin/Store/Cache.hs
@@ -75,7 +75,7 @@
                                             xPubBalsTxs, xPubBalsUnspents,
                                             xPubTxs)
 import           Haskoin.Store.Data        (Balance (..), BlockData (..),
-                                            BlockRef (..), BlockTx (..),
+                                            BlockRef (..), TxRef (..),
                                             DeriveType (..), Prev (..),
                                             TxData (..), Unspent (..),
                                             XPubBal (..), XPubSpec (..),
@@ -170,7 +170,7 @@
        (MonadUnliftIO m, MonadLoggerIO m, StoreRead m)
     => XPubSpec
     -> Limits
-    -> CacheX m [BlockTx]
+    -> CacheX m [TxRef]
 getXPubTxs xpub limits = do
     xpubtxt <- xpubText xpub
     $(logDebugS) "Cache" $ "Getting xpub txs for " <> xpubtxt
@@ -285,7 +285,7 @@
        (StoreRead m, MonadLoggerIO m)
     => XPubSpec
     -> Limits
-    -> CacheX m [BlockTx]
+    -> CacheX m [TxRef]
 cacheGetXPubTxs xpub limits = do
     score <-
         case start limits of
@@ -307,7 +307,7 @@
     touchKeys [xpub]
     return $ map (uncurry f) xs
   where
-    f t s = BlockTx {blockTxHash = t, blockTxBlock = scoreBlockRef s}
+    f t s = TxRef {txRefHash = t, txRefBlock = scoreBlockRef s}
 
 cacheGetXPubUnspents ::
        (StoreRead m, MonadLoggerIO m)
@@ -849,9 +849,9 @@
                 x <-
                     redisAddXPubTxs
                         (addressXPubSpec i)
-                        [ BlockTx
-                              { blockTxHash = txHash (txData tx)
-                              , blockTxBlock = txDataBlock tx
+                        [ TxRef
+                              { txRefHash = txHash (txData tx)
+                              , txRefBlock = txDataBlock tx
                               }
                         ]
                 y <- uns p i
@@ -877,9 +877,9 @@
                         b@MemRef {} ->
                             redisAddToMempool $
                             (: [])
-                                BlockTx
-                                    { blockTxHash = txHash (txData tx)
-                                    , blockTxBlock = b
+                                TxRef
+                                    { txRefHash = txHash (txData tx)
+                                    , txRefBlock = b
                                     }
                         _ -> redisRemFromMempool [txHash (txData tx)]
                 return $ a >> b >> return ()
@@ -977,8 +977,8 @@
 
 syncMempoolC :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => CacheX m ()
 syncMempoolC = do
-    nodepool <- (HashSet.fromList . map blockTxHash) <$> lift getMempool
-    cachepool <- (HashSet.fromList . map blockTxHash) <$> cacheGetMempool
+    nodepool <- (HashSet.fromList . map txRefHash) <$> lift getMempool
+    cachepool <- (HashSet.fromList . map txRefHash) <$> cacheGetMempool
     txs <-
         mapM getit . HashSet.toList $
         mappend
@@ -1000,7 +1000,7 @@
             Nothing -> return (Left th)
             Just tx -> return (Right tx)
 
-cacheGetMempool :: MonadLoggerIO m => CacheX m [BlockTx]
+cacheGetMempool :: MonadLoggerIO m => CacheX m [TxRef]
 cacheGetMempool = runRedis redisGetMempool
 
 cacheGetHead :: MonadLoggerIO m => CacheX m (Maybe BlockHash)
@@ -1038,11 +1038,11 @@
        MonadLoggerIO m => [Address] -> CacheX m [Maybe AddressXPub]
 cacheGetAddrsInfo as = runRedis (redisGetAddrsInfo as)
 
-redisAddToMempool :: (Applicative f, RedisCtx m f) => [BlockTx] -> m (f Integer)
+redisAddToMempool :: (Applicative f, RedisCtx m f) => [TxRef] -> m (f Integer)
 redisAddToMempool [] = return (pure 0)
 redisAddToMempool btxs =
     zadd mempoolSetKey $
-    map (\btx -> (blockRefScore (blockTxBlock btx), encode (blockTxHash btx)))
+    map (\btx -> (blockRefScore (txRefBlock btx), encode (txRefHash btx)))
         btxs
 
 redisRemFromMempool ::
@@ -1099,11 +1099,11 @@
             return $ addrs' + txset' + utxo' + bal'
 
 redisAddXPubTxs ::
-       (Applicative f, RedisCtx m f) => XPubSpec -> [BlockTx] -> m (f Integer)
+       (Applicative f, RedisCtx m f) => XPubSpec -> [TxRef] -> m (f Integer)
 redisAddXPubTxs _ [] = return (pure 0)
 redisAddXPubTxs xpub btxs =
     zadd (txSetPfx <> encode xpub) $
-    map (\t -> (blockRefScore (blockTxBlock t), encode (blockTxHash t))) btxs
+    map (\t -> (blockRefScore (txRefBlock t), encode (txRefHash t))) btxs
 
 redisRemXPubTxs ::
        (Applicative f, RedisCtx m f) => XPubSpec -> [TxHash] -> m (f Integer)
@@ -1207,14 +1207,14 @@
     x <- Redis.get bestBlockKey
     return $ (eitherToMaybe . decode =<<) <$> x
 
-redisGetMempool :: (Applicative f, RedisCtx m f) => m (f [BlockTx])
+redisGetMempool :: (Applicative f, RedisCtx m f) => m (f [TxRef])
 redisGetMempool = do
     xs <- getFromSortedSet mempoolSetKey Nothing 0 0
     return $ do
         ys <- xs
         return $ map (uncurry f) ys
   where
-    f t s = BlockTx {blockTxBlock = scoreBlockRef s, blockTxHash = t}
+    f t s = TxRef {txRefBlock = scoreBlockRef s, txRefHash = t}
 
 xpubText :: (MonadUnliftIO m, MonadLoggerIO m, StoreRead m) => XPubSpec -> CacheX m Text
 xpubText xpub = do
diff --git a/src/Haskoin/Store/Common.hs b/src/Haskoin/Store/Common.hs
--- a/src/Haskoin/Store/Common.hs
+++ b/src/Haskoin/Store/Common.hs
@@ -51,7 +51,7 @@
                                             txHash)
 import           Haskoin.Node              (Peer)
 import           Haskoin.Store.Data        (Balance (..), BlockData (..),
-                                            BlockTx (..), DeriveType (..),
+                                            TxRef (..), DeriveType (..),
                                             Spender, Transaction, TxData,
                                             UnixTime, Unspent (..),
                                             XPubBal (..), XPubSpec (..),
@@ -99,14 +99,14 @@
     getBalance a = head <$> getBalances [a]
     getBalances :: [Address] -> m [Balance]
     getBalances as = mapM getBalance as
-    getAddressesTxs :: [Address] -> Limits -> m [BlockTx]
-    getAddressTxs :: Address -> Limits -> m [BlockTx]
+    getAddressesTxs :: [Address] -> Limits -> m [TxRef]
+    getAddressTxs :: Address -> Limits -> m [TxRef]
     getAddressTxs a = getAddressesTxs [a]
     getUnspent :: OutPoint -> m (Maybe Unspent)
     getAddressUnspents :: Address -> Limits -> m [Unspent]
     getAddressUnspents a = getAddressesUnspents [a]
     getAddressesUnspents :: [Address] -> Limits -> m [Unspent]
-    getMempool :: m [BlockTx]
+    getMempool :: m [TxRef]
     xPubBals :: XPubSpec -> m [XPubBal]
     xPubBals xpub = do
         igap <- getInitialGap
@@ -176,12 +176,12 @@
                              XPubUnspent {xPubUnspentPath = p, xPubUnspent = t})
                         uns
             (xuns <>) <$> go xs
-    xPubTxs :: XPubSpec -> Limits -> m [BlockTx]
+    xPubTxs :: XPubSpec -> Limits -> m [TxRef]
     xPubTxs xpub limits = do
         bs <- xPubBals xpub
         let as = map (balanceAddress . xPubBal) bs
         ts <- concat <$> mapM (\a -> getAddressTxs a (deOffset limits)) as
-        let ts' = sortBy (flip compare `on` blockTxBlock) (nub' ts)
+        let ts' = sortBy (flip compare `on` txRefBlock) (nub' ts)
         return $ applyLimits limits ts'
     getMaxGap :: m Word32
     getInitialGap :: m Word32
@@ -193,11 +193,11 @@
     insertTx :: TxData -> m ()
     insertSpender :: OutPoint -> Spender -> m ()
     deleteSpender :: OutPoint -> m ()
-    insertAddrTx :: Address -> BlockTx -> m ()
-    deleteAddrTx :: Address -> BlockTx -> m ()
+    insertAddrTx :: Address -> TxRef -> m ()
+    deleteAddrTx :: Address -> TxRef -> m ()
     insertAddrUnspent :: Address -> Unspent -> m ()
     deleteAddrUnspent :: Address -> Unspent -> m ()
-    setMempool :: [BlockTx] -> m ()
+    setMempool :: [TxRef] -> m ()
     setBalance :: Balance -> m ()
     insertUnspent :: Unspent -> m ()
     deleteUnspent :: OutPoint -> m ()
@@ -233,11 +233,11 @@
        StoreRead m
     => [XPubBal]
     -> Limits
-    -> m [BlockTx]
+    -> m [TxRef]
 xPubBalsTxs bals limits = do
     let as = map balanceAddress . filter (not . nullBalance) $ map xPubBal bals
     ts <- concat <$> mapM (\a -> getAddressTxs a (deOffset limits)) as
-    let ts' = sortBy (flip compare `on` blockTxBlock) (nub' ts)
+    let ts' = sortBy (flip compare `on` txRefBlock) (nub' ts)
     return $ applyLimits limits ts'
 
 getTransaction ::
diff --git a/src/Haskoin/Store/Database/Memory.hs b/src/Haskoin/Store/Database/Memory.hs
--- a/src/Haskoin/Store/Database/Memory.hs
+++ b/src/Haskoin/Store/Database/Memory.hs
@@ -25,7 +25,7 @@
                                                headerHash, txHash)
 import           Haskoin.Store.Common         (StoreRead (..), StoreWrite (..))
 import           Haskoin.Store.Data           (Balance (..), BlockData (..),
-                                               BlockRef (..), BlockTx (..),
+                                               BlockRef (..), TxRef (..),
                                                Spender, TxData (..),
                                                Unspent (..), zeroBalance)
 import           Haskoin.Store.Database.Types (BalVal, OutVal (..), UnspentVal,
@@ -58,7 +58,7 @@
     , hBalance :: !(HashMap Address BalVal)
     , hAddrTx :: !(HashMap Address (HashMap BlockRef (HashMap TxHash Bool)))
     , hAddrOut :: !(HashMap Address (HashMap BlockRef (HashMap OutPoint (Maybe OutVal))))
-    , hMempool :: !(Maybe [BlockTx])
+    , hMempool :: !(Maybe [TxRef])
     } deriving (Eq, Show)
 
 emptyMemoryDatabase :: MemoryDatabase
@@ -101,7 +101,7 @@
     fromMaybe (zeroBalance a) . fmap (valToBalance a) . M.lookup a $
     hBalance mem
 
-getMempoolH :: MemoryDatabase -> Maybe [BlockTx]
+getMempoolH :: MemoryDatabase -> Maybe [TxRef]
 getMempoolH = hMempool
 
 setBestH :: BlockHash -> MemoryDatabase -> MemoryDatabase
@@ -145,24 +145,24 @@
   where
     b = balanceToVal bal
 
-insertAddrTxH :: Address -> BlockTx -> MemoryDatabase -> MemoryDatabase
+insertAddrTxH :: Address -> TxRef -> MemoryDatabase -> MemoryDatabase
 insertAddrTxH a btx db =
     let s =
             M.singleton
                 a
                 (M.singleton
-                     (blockTxBlock btx)
-                     (M.singleton (blockTxHash btx) True))
+                     (txRefBlock btx)
+                     (M.singleton (txRefHash btx) True))
      in db {hAddrTx = M.unionWith (M.unionWith M.union) s (hAddrTx db)}
 
-deleteAddrTxH :: Address -> BlockTx -> MemoryDatabase -> MemoryDatabase
+deleteAddrTxH :: Address -> TxRef -> MemoryDatabase -> MemoryDatabase
 deleteAddrTxH a btx db =
     let s =
             M.singleton
                 a
                 (M.singleton
-                     (blockTxBlock btx)
-                     (M.singleton (blockTxHash btx) False))
+                     (txRefBlock btx)
+                     (M.singleton (txRefHash btx) False))
      in db {hAddrTx = M.unionWith (M.unionWith M.union) s (hAddrTx db)}
 
 insertAddrUnspentH :: Address -> Unspent -> MemoryDatabase -> MemoryDatabase
@@ -190,7 +190,7 @@
                      (M.singleton (unspentPoint u) Nothing))
      in db {hAddrOut = M.unionWith (M.unionWith M.union) s (hAddrOut db)}
 
-setMempoolH :: [BlockTx] -> MemoryDatabase -> MemoryDatabase
+setMempoolH :: [TxRef] -> MemoryDatabase -> MemoryDatabase
 setMempoolH xs db = db {hMempool = Just xs}
 
 getUnspentH :: OutPoint -> MemoryDatabase -> Maybe (Maybe Unspent)
diff --git a/src/Haskoin/Store/Database/Reader.hs b/src/Haskoin/Store/Database/Reader.hs
--- a/src/Haskoin/Store/Database/Reader.hs
+++ b/src/Haskoin/Store/Database/Reader.hs
@@ -30,17 +30,16 @@
                                                StoreRead (..), applyLimits,
                                                applyLimitsC, deOffset, nub')
 import           Haskoin.Store.Data           (Balance, BlockData,
-                                               BlockRef (..), BlockTx (..),
-                                               Spender, TxData (..),
+                                               BlockRef (..), Spender,
+                                               TxData (..), TxRef (..),
                                                Unspent (..), zeroBalance)
 import           Haskoin.Store.Database.Types (AddrOutKey (..), AddrTxKey (..),
                                                BalKey (..), BestKey (..),
                                                BlockKey (..), HeightKey (..),
-                                               MemKey (..), OldMemKey (..),
-                                               SpenderKey (..), TxKey (..),
-                                               UnspentKey (..), VersionKey (..),
-                                               toUnspent, valToBalance,
-                                               valToUnspent)
+                                               MemKey (..), SpenderKey (..),
+                                               TxKey (..), UnspentKey (..),
+                                               VersionKey (..), toUnspent,
+                                               valToBalance, valToUnspent)
 import           UnliftIO                     (MonadIO, liftIO)
 
 type DatabaseReaderT = ReaderT DatabaseReader
@@ -84,26 +83,18 @@
 withDatabaseReader = flip runReaderT
 
 initRocksDB :: MonadIO m => DatabaseReader -> m ()
-initRocksDB bdb@DatabaseReader {databaseReadOptions = opts, databaseHandle = db} = do
+initRocksDB DatabaseReader {databaseReadOptions = opts, databaseHandle = db} = do
     e <-
         runExceptT $
         retrieve db opts VersionKey >>= \case
             Just v
                 | v == dataVersion -> return ()
-                | v == 15 -> migrate15to16 bdb >> initRocksDB bdb
                 | otherwise -> throwError "Incorrect RocksDB database version"
             Nothing -> setInitRocksDB db
     case e of
         Left s   -> error s
         Right () -> return ()
 
-migrate15to16 :: MonadIO m => DatabaseReader -> m ()
-migrate15to16 DatabaseReader {databaseReadOptions = opts, databaseHandle = 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)
-
 setInitRocksDB :: MonadIO m => DB -> m ()
 setInitRocksDB db = insert db VersionKey dataVersion
 
@@ -145,21 +136,21 @@
     fromMaybe (zeroBalance a) . fmap (valToBalance a) <$>
     retrieve db opts (BalKey a)
 
-getMempoolDB :: MonadIO m => DatabaseReader -> m [BlockTx]
+getMempoolDB :: MonadIO m => DatabaseReader -> m [TxRef]
 getMempoolDB DatabaseReader {databaseReadOptions = opts, databaseHandle = db} =
     fmap f . fromMaybe [] <$> retrieve db opts MemKey
   where
-    f (t, h) = BlockTx {blockTxBlock = MemRef t, blockTxHash = h}
+    f (t, h) = TxRef {txRefBlock = MemRef t, txRefHash = h}
 
 getAddressesTxsDB ::
        MonadIO m
     => [Address]
     -> Limits
     -> DatabaseReader
-    -> m [BlockTx]
+    -> m [TxRef]
 getAddressesTxsDB addrs limits db = do
     ts <- concat <$> mapM (\a -> getAddressTxsDB a (deOffset limits) db) addrs
-    let ts' = sortBy (flip compare `on` blockTxBlock) (nub' ts)
+    let ts' = sortBy (flip compare `on` txRefBlock) (nub' ts)
     return $ applyLimits limits ts'
 
 getAddressTxsDB ::
@@ -167,7 +158,7 @@
     => Address
     -> Limits
     -> DatabaseReader
-    -> m [BlockTx]
+    -> m [TxRef]
 getAddressTxsDB a limits bdb@DatabaseReader { databaseReadOptions = opts
                                             , databaseHandle = db
                                             } =
diff --git a/src/Haskoin/Store/Database/Types.hs b/src/Haskoin/Store/Database/Types.hs
--- a/src/Haskoin/Store/Database/Types.hs
+++ b/src/Haskoin/Store/Database/Types.hs
@@ -10,7 +10,6 @@
     , BalKey(..)
     , HeightKey(..)
     , MemKey(..)
-    , OldMemKey(..)
     , SpenderKey(..)
     , TxKey(..)
     , UnspentKey(..)
@@ -42,14 +41,13 @@
                                          OutPoint (..), TxHash, eitherToMaybe,
                                          scriptToAddressBS)
 import           Haskoin.Store.Data     (Balance (..), BlockData, BlockRef,
-                                         BlockTx (..), Spender, TxData,
-                                         UnixTime, Unspent (..), getUnixTime,
-                                         putUnixTime)
+                                         Spender, TxData, TxRef (..), UnixTime,
+                                         Unspent (..))
 
 -- | Database key for an address transaction.
 data AddrTxKey
     = AddrTxKey { addrTxKeyA :: !Address
-                , addrTxKeyT :: !BlockTx
+                , addrTxKeyT :: !TxRef
                 }
       -- ^ key for a transaction affecting an address
     | AddrTxKeyA { addrTxKeyA :: !Address }
@@ -62,11 +60,9 @@
 
 instance Serialize AddrTxKey
     -- 0x05 · Address · BlockRef · TxHash
-                                                               where
+                                          where
     put AddrTxKey { addrTxKeyA = a
-                  , addrTxKeyT = BlockTx { blockTxBlock = b
-                                         , blockTxHash = t
-                                         }
+                  , addrTxKeyT = TxRef {txRefBlock = b, txRefHash = t}
                   } = do
         putWord8 0x05
         put a
@@ -91,11 +87,7 @@
         return
             AddrTxKey
                 { addrTxKeyA = a
-                , addrTxKeyT =
-                      BlockTx
-                          { blockTxBlock = b
-                          , blockTxHash = t
-                          }
+                , addrTxKeyT = TxRef {txRefBlock = b, txRefHash = t}
                 }
 
 instance Key AddrTxKey
@@ -324,38 +316,6 @@
 
 instance Key VersionKey
 instance 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 Key OldMemKey
-instance KeyValue OldMemKey ()
 
 data BalVal = BalVal
     { balValAmount        :: !Word64
diff --git a/src/Haskoin/Store/Database/Writer.hs b/src/Haskoin/Store/Database/Writer.hs
--- a/src/Haskoin/Store/Database/Writer.hs
+++ b/src/Haskoin/Store/Database/Writer.hs
@@ -9,7 +9,6 @@
 
 import           Control.Applicative           ((<|>))
 import           Control.Monad                 (join)
-import           Control.Monad.Except          (MonadError)
 import           Control.Monad.Reader          (ReaderT)
 import qualified Control.Monad.Reader          as R
 import           Control.Monad.Trans.Maybe     (MaybeT (..), runMaybeT)
@@ -26,7 +25,7 @@
                                                 OutPoint (..), TxHash)
 import           Haskoin.Store.Common          (StoreRead (..), StoreWrite (..))
 import           Haskoin.Store.Data            (Balance, BlockData,
-                                                BlockRef (..), BlockTx (..),
+                                                BlockRef (..), TxRef (..),
                                                 Spender, TxData, Unspent,
                                                 nullBalance, zeroBalance)
 import           Haskoin.Store.Database.Memory (MemoryDatabase (..),
@@ -52,7 +51,7 @@
     }
 
 runDatabaseWriter ::
-       (MonadIO m, MonadError e m)
+       MonadIO m
     => DatabaseReader
     -> ReaderT DatabaseWriter m a
     -> m a
@@ -133,9 +132,9 @@
             (AddrTxKey
                  { addrTxKeyA = a
                  , addrTxKeyT =
-                       BlockTx
-                           { blockTxBlock = b
-                           , blockTxHash = t
+                       TxRef
+                           { txRefBlock = b
+                           , txRefHash = t
                            }
                  })
             ()
@@ -144,9 +143,9 @@
             AddrTxKey
                 { addrTxKeyA = a
                 , addrTxKeyT =
-                      BlockTx
-                          { blockTxBlock = b
-                          , blockTxHash = t
+                      TxRef
+                          { txRefBlock = b
+                          , txRefHash = t
                           }
                 }
 
@@ -164,10 +163,10 @@
     h a b p Nothing =
         deleteOp AddrOutKey {addrOutKeyA = a, addrOutKeyB = b, addrOutKeyP = p}
 
-mempoolOp :: [BlockTx] -> BatchOp
+mempoolOp :: [TxRef] -> BatchOp
 mempoolOp =
     insertOp MemKey .
-    map (\BlockTx {blockTxBlock = MemRef t, blockTxHash = h} -> (t, h))
+    map (\TxRef {txRefBlock = MemRef t, txRefHash = h} -> (t, h))
 
 unspentOps :: HashMap TxHash (IntMap (Maybe UnspentVal)) -> [BatchOp]
 unspentOps = concatMap (uncurry f) . M.toList
@@ -200,11 +199,11 @@
 deleteSpenderI p DatabaseWriter {databaseWriterState = hm} =
     withMemoryDatabase hm $ deleteSpender p
 
-insertAddrTxI :: MonadIO m => Address -> BlockTx -> DatabaseWriter -> m ()
+insertAddrTxI :: MonadIO m => Address -> TxRef -> DatabaseWriter -> m ()
 insertAddrTxI a t DatabaseWriter {databaseWriterState = hm} =
     withMemoryDatabase hm $ insertAddrTx a t
 
-deleteAddrTxI :: MonadIO m => Address -> BlockTx -> DatabaseWriter -> m ()
+deleteAddrTxI :: MonadIO m => Address -> TxRef -> DatabaseWriter -> m ()
 deleteAddrTxI a t DatabaseWriter {databaseWriterState = hm} =
     withMemoryDatabase hm $ deleteAddrTx a t
 
@@ -216,7 +215,7 @@
 deleteAddrUnspentI a u DatabaseWriter {databaseWriterState = hm} =
     withMemoryDatabase hm $ deleteAddrUnspent a u
 
-setMempoolI :: MonadIO m => [BlockTx] -> DatabaseWriter -> m ()
+setMempoolI :: MonadIO m => [TxRef] -> DatabaseWriter -> m ()
 setMempoolI xs DatabaseWriter {databaseWriterState = hm} = withMemoryDatabase hm $ setMempool xs
 
 getBestBlockI :: MonadIO m => DatabaseWriter -> m (Maybe BlockHash)
@@ -304,7 +303,7 @@
 getMempoolI ::
        MonadIO m
     => DatabaseWriter
-    -> m [BlockTx]
+    -> m [TxRef]
 getMempoolI DatabaseWriter {databaseWriterState = hm, databaseWriterReader = db} =
     getMempoolH <$> readTVarIO (memoryDatabase hm) >>= \case
         Just xs -> return xs
diff --git a/src/Haskoin/Store/Logic.hs b/src/Haskoin/Store/Logic.hs
--- a/src/Haskoin/Store/Logic.hs
+++ b/src/Haskoin/Store/Logic.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE FlexibleContexts  #-}
 {-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards   #-}
 {-# LANGUAGE TemplateHaskell   #-}
 module Haskoin.Store.Logic
     ( ImportException (..)
@@ -10,20 +11,22 @@
     , revertBlock
     , importBlock
     , newMempoolTx
-    , deleteTx
+    , delTx
     ) where
 
 import           Control.Monad           (forM, forM_, guard, unless, void,
                                           when, zipWithM_)
-import           Control.Monad.Except    (MonadError (..))
-import           Control.Monad.Logger    (MonadLogger, logDebugS, logErrorS,
+import           Control.Monad.Logger    (MonadLoggerIO, logDebugS, logErrorS,
                                           logWarnS)
 import qualified Data.ByteString         as B
 import qualified Data.ByteString.Short   as B.Short
 import           Data.Either             (rights)
+import           Data.HashMap.Strict     (HashMap)
+import qualified Data.HashMap.Strict     as HashMap
+import qualified Data.HashSet            as HashSet
 import qualified Data.IntMap.Strict      as I
-import           Data.List               (sort, nub)
-import           Data.Maybe              (fromMaybe, isNothing)
+import           Data.List               (nub, sort)
+import           Data.Maybe              (catMaybes, fromMaybe, isNothing)
 import           Data.Serialize          (encode)
 import           Data.String             (fromString)
 import           Data.String.Conversions (cs)
@@ -42,11 +45,13 @@
 import           Haskoin.Store.Common    (StoreRead (..), StoreWrite (..), nub',
                                           sortTxs)
 import           Haskoin.Store.Data      (Balance (..), BlockData (..),
-                                          BlockRef (..), BlockTx (..),
-                                          Prev (..), Spender (..), TxData (..),
+                                          BlockRef (..), Prev (..),
+                                          Spender (..), TxData (..), TxRef (..),
                                           UnixTime, Unspent (..), confirmed,
                                           nullBalance)
-import           UnliftIO                (Exception)
+import           UnliftIO                (Async, Exception, MonadUnliftIO, TVar,
+                                          async, atomically, modifyTVar,
+                                          newTVarIO, readTVarIO, throwIO, wait)
 
 data ImportException
     = PrevBlockNotBest !Text
@@ -72,11 +77,72 @@
     | DuplicatePrevOutput !Text
     deriving (Show, Read, Eq, Ord, Exception)
 
+data BlockAccel =
+    BlockAccel
+        { utxas :: !(TVar (HashMap OutPoint (Async (Maybe Unspent))))
+        , balas :: !(TVar (HashMap Address (Async Balance)))
+        }
+
+accelTxs :: (MonadUnliftIO m, StoreRead m) => [Tx] -> m BlockAccel
+accelTxs txs = do
+    utxas' <-
+        fmap HashMap.fromList $
+        forM inops $ \op -> do
+            a <- async (getUnspent op)
+            return (op, a)
+    let f tx = map g (txOut tx)
+        g to =
+            case scriptToAddressBS (scriptOutput to) of
+                Left _  -> Nothing
+                Right a -> Just a
+        oaddrs = catMaybes (concatMap f txs)
+    balas' <-
+        fmap HashMap.fromList $
+        forM oaddrs $ \a -> do
+            a' <- async (getBalance a)
+            return (a, a')
+    utxas <- newTVarIO utxas'
+    balas <- newTVarIO balas'
+    return BlockAccel {..}
+  where
+    newops = HashSet.fromList (map txHash txs)
+    inops =
+        filter
+            (not . (`HashSet.member` newops) . outPointHash)
+            (concatMap (map prevOutput . txIn) txs)
+
+getAccelBalance ::
+       (MonadUnliftIO m, StoreRead m) => BlockAccel -> Address -> m Balance
+getAccelBalance BlockAccel {..} a = do
+    balas' <- readTVarIO balas
+    case HashMap.lookup a balas' of
+        Nothing -> getBalance a
+        Just a' -> wait a'
+
+delAccelBalance :: (MonadUnliftIO m) => BlockAccel -> Address -> m ()
+delAccelBalance BlockAccel {..} a =
+    atomically $ modifyTVar balas (HashMap.delete a)
+
+getAccelUnspent ::
+       (MonadUnliftIO m, StoreRead m)
+    => BlockAccel
+    -> OutPoint
+    -> m (Maybe Unspent)
+getAccelUnspent BlockAccel {..} op = do
+    utxas' <- readTVarIO utxas
+    case HashMap.lookup op utxas' of
+        Nothing -> getUnspent op
+        Just a -> wait a
+
+delAccelUnspent :: (MonadUnliftIO m) => BlockAccel -> OutPoint -> m ()
+delAccelUnspent BlockAccel {..} op =
+    atomically $ modifyTVar utxas (HashMap.delete op)
+
 initBest ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
     => m ()
 initBest = do
@@ -88,11 +154,15 @@
 
 getOldMempool :: StoreRead m => UnixTime -> m [TxHash]
 getOldMempool now =
-    map blockTxHash . filter ((< now - 3600 * 72) . memRefTime . blockTxBlock) <$>
+    map txRefHash . filter ((< now - 3600 * 72) . memRefTime . txRefBlock) <$>
     getMempool
 
 newMempoolTx ::
-       (StoreRead m, StoreWrite m, MonadLogger m, MonadError ImportException m)
+       ( StoreRead m
+       , StoreWrite m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
+       )
     => Tx
     -> UnixTime
     -> m (Maybe [TxHash])
@@ -104,13 +174,15 @@
                 $(logDebugS) "BlockStore" $
                     "Transaction already in store: " <> txHashToHex (txHash tx)
                 return Nothing
-        _ -> Just <$> importTx (MemRef w) w tx
+        _ -> do
+            accel <- accelTxs [tx]
+            Just <$> importTx accel (MemRef w) w tx
 
 revertBlock ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
     => BlockHash
     -> m [TxHash]
@@ -119,23 +191,24 @@
         getBestBlock >>= \case
             Nothing -> do
                 $(logErrorS) "BlockStore" "Best block unknown"
-                throwError BestBlockUnknown
+                throwIO BestBlockUnknown
             Just h ->
                 getBlock h >>= \case
                     Nothing -> do
                         $(logErrorS) "BlockStore" "Best block not found"
-                        throwError (BestBlockNotFound (blockHashToHex h))
+                        throwIO (BestBlockNotFound (blockHashToHex h))
                     Just b
                         | h == bh -> return b
                         | otherwise -> do
                             $(logErrorS) "BlockStore" $
                                 "Cannot delete block that is not head: " <>
                                 blockHashToHex h
-                            throwError (BlockNotBest (blockHashToHex bh))
+                            throwIO (BlockNotBest (blockHashToHex bh))
     txs <- mapM (fmap txData . getImportTxData) (blockDataTxs bd)
+    accel <- accelTxs txs
     ths <-
         nub' . concat <$>
-        mapM (deleteTx False False . txHash . snd) (reverse (sortTxs txs))
+        mapM (deleteTx accel False False . txHash . snd) (reverse (sortTxs txs))
     setBest (prevBlock (blockDataHeader bd))
     insertBlock bd {blockDataMainChain = False}
     return ths
@@ -143,14 +216,14 @@
 importBlock ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
     => Block
     -> BlockNode
     -> m [TxHash] -- ^ deleted transactions
 importBlock b n = do
-    mp <- filter (`elem` bths) . map blockTxHash <$> getMempool
+    mp <- filter (`elem` bths) . map txRefHash <$> getMempool
     getBestBlock >>= \case
         Nothing
             | isGenesis n -> return ()
@@ -158,16 +231,17 @@
                 $(logErrorS) "BlockStore" $
                     "Cannot import non-genesis block at this point: " <>
                     blockHashToHex (headerHash (blockHeader b))
-                throwError BestBlockUnknown
+                throwIO BestBlockUnknown
         Just h
             | prevBlock (blockHeader b) == h -> return ()
             | otherwise -> do
                 $(logErrorS) "BlockStore" $
                     "Block does not build on head: " <>
                     blockHashToHex (headerHash (blockHeader b))
-                throwError $
+                throwIO $
                     PrevBlockNotBest (blockHashToHex (prevBlock (nodeHeader n)))
     net <- getNetwork
+    accel <- accelTxs (blockTxns b)
     let subsidy = computeSubsidy net (nodeHeight n)
     insertBlock
         BlockData
@@ -186,26 +260,25 @@
             , blockDataOutputs = ts_out_val
             }
     bs <- getBlocksAtHeight (nodeHeight n)
-    setBlocksAtHeight
-        (nub (headerHash (nodeHeader n) : bs))
-        (nodeHeight n)
+    setBlocksAtHeight (nub (headerHash (nodeHeader n) : bs)) (nodeHeight n)
     setBest (headerHash (nodeHeader n))
     ths <-
         nub' . concat <$>
-        mapM (uncurry (import_or_confirm mp)) (sortTxs (blockTxns b))
+        mapM (uncurry (import_or_confirm accel mp)) (sortTxs (blockTxns b))
     return ths
   where
     bths = map txHash (blockTxns b)
-    import_or_confirm mp x tx =
+    import_or_confirm accel mp x tx =
         if txHash tx `elem` mp
             then getTxData (txHash tx) >>= \case
-                     Just td -> confirmTx td (br x) tx >> return []
+                     Just td -> confirmTx accel td (br x) tx >> return []
                      Nothing -> do
                          $(logErrorS) "BlockStore" $
                              "Cannot get data for mempool tx: " <>
                              txHashToHex (txHash tx)
-                         throwError $ TxNotFound (txHashToHex (txHash tx))
+                         throwIO $ TxNotFound (txHashToHex (txHash tx))
             else importTx
+                     accel
                      (br x)
                      (fromIntegral (blockTimestamp (nodeHeader n)))
                      tx
@@ -223,14 +296,15 @@
 importTx ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => BlockRef
+    => BlockAccel
+    -> BlockRef
     -> Word64 -- ^ unix time
     -> Tx
     -> m [TxHash] -- ^ deleted transactions
-importTx br tt tx = do
+importTx accel br tt tx = do
     unless (confirmed br) $ do
         $(logDebugS) "BlockStore" $
             "Importing transaction " <> txHashToHex (txHash tx)
@@ -238,12 +312,12 @@
             $(logErrorS) "BlockStore" $
                 "Transaction spends same output twice: " <>
                 txHashToHex (txHash tx)
-            throwError (DuplicatePrevOutput (txHashToHex (txHash tx)))
+            throwIO (DuplicatePrevOutput (txHashToHex (txHash tx)))
         when iscb $ do
             $(logErrorS) "BlockStore" $
                 "Coinbase cannot be imported into mempool: " <>
                 txHashToHex (txHash tx)
-            throwError (UnconfirmedCoinbase (txHashToHex (txHash tx)))
+            throwIO (UnconfirmedCoinbase (txHashToHex (txHash tx)))
     us' <-
         if iscb
             then return []
@@ -255,15 +329,15 @@
          sum (map unspentAmount us) < sum (map outValue (txOut tx))) $ do
         $(logErrorS) "BlockStore" $
             "Insufficient funds for tx: " <> txHashToHex (txHash tx)
-        throwError (InsufficientFunds (txHashToHex th))
+        throwIO (InsufficientFunds (txHashToHex th))
     rbf <- isRBF br tx
     commit rbf us
     return ths
   where
     commit rbf us = do
-        zipWithM_ (spendOutput br (txHash tx)) [0 ..] us
+        zipWithM_ (spendOutput accel br (txHash tx)) [0 ..] us
         zipWithM_
-            (\i o -> newOutput br (OutPoint (txHash tx) i) o)
+            (\i o -> newOutput accel br (OutPoint (txHash tx) i) o)
             [0 ..]
             (txOut tx)
         let ps =
@@ -281,10 +355,10 @@
                     , txDataTime = tt
                     }
         insertTx d
-        updateAddressCounts (txDataAddresses d) (+ 1)
+        updateAddressCounts accel (txDataAddresses d) (+ 1)
         unless (confirmed br) $ insertIntoMempool (txHash tx) (memRefTime br)
     uns op =
-        getUnspent op >>= \case
+        getAccelUnspent accel op >>= \case
             Just u -> return (u, [])
             Nothing -> do
                 $(logWarnS) "BlockStore" $
@@ -301,13 +375,13 @@
                             fromString (show (outPointIndex op))
                         $(logErrorS) "BlockStore" $
                             "Orphan tx: " <> txHashToHex (txHash tx)
-                        throwError (TxOrphan (txHashToHex (txHash tx)))
+                        throwIO (TxOrphan (txHashToHex (txHash tx)))
                     Just Spender {spenderHash = s} -> do
                         $(logWarnS) "BlockStore" $
                             "Deleting transaction " <> txHashToHex s <>
                             " because it conflicts with " <>
                             txHashToHex (txHash tx)
-                        ths <- deleteTx True (not (confirmed br)) s
+                        ths <- deleteTx accel True (not (confirmed br)) s
                         getUnspent op >>= \case
                             Nothing -> do
                                 $(logErrorS) "BlockStore" $
@@ -315,7 +389,7 @@
                                     txHashToHex (outPointHash op) <>
                                     " " <>
                                     fromString (show (outPointIndex op))
-                                throwError (OutputSpent (cs (show op)))
+                                throwIO (OutputSpent (cs (show op)))
                             Just u -> return (u, ths)
     th = txHash tx
     iscb = all (== nullOutPoint) (map prevOutput (txIn tx))
@@ -324,30 +398,32 @@
 confirmTx ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => TxData
+    => BlockAccel
+    -> TxData
     -> BlockRef
     -> Tx
     -> m ()
-confirmTx t br tx = do
+confirmTx accel t br tx = do
     forM_ (txDataPrevs t) $ \p ->
         case scriptToAddressBS (prevScript p) of
             Left _ -> return ()
             Right a -> do
                 deleteAddrTx
                     a
-                    BlockTx
-                        {blockTxBlock = txDataBlock t, blockTxHash = txHash tx}
+                    TxRef
+                        {txRefBlock = txDataBlock t, txRefHash = txHash tx}
                 insertAddrTx
                     a
-                    BlockTx {blockTxBlock = br, blockTxHash = txHash tx}
+                    TxRef {txRefBlock = br, txRefHash = txHash tx}
     forM_ (zip [0 ..] (txOut tx)) $ \(n, o) -> do
         let op = OutPoint (txHash tx) n
         s <- getSpender (OutPoint (txHash tx) n)
         when (isNothing s) $ do
             deleteUnspent op
+            delAccelUnspent accel op
             insertUnspent
                 Unspent
                     { unspentBlock = br
@@ -362,11 +438,11 @@
             Right a -> do
                 deleteAddrTx
                     a
-                    BlockTx
-                        {blockTxBlock = txDataBlock t, blockTxHash = txHash tx}
+                    TxRef
+                        {txRefBlock = txDataBlock t, txRefHash = txHash tx}
                 insertAddrTx
                     a
-                    BlockTx {blockTxBlock = br, blockTxHash = txHash tx}
+                    TxRef {txRefBlock = br, txRefHash = txHash tx}
                 when (isNothing s) $ do
                     deleteAddrUnspent
                         a
@@ -390,38 +466,62 @@
                                   eitherToMaybe
                                       (scriptToAddressBS (scriptOutput o))
                             }
-                    reduceBalance False False a (outValue o)
-                    increaseBalance True False a (outValue o)
+                    reduceBalance accel False False a (outValue o)
+                    increaseBalance accel True False a (outValue o)
     insertTx t {txDataBlock = br}
     deleteFromMempool (txHash tx)
 
 deleteFromMempool :: (Monad m, StoreRead m, StoreWrite m) => TxHash -> m ()
 deleteFromMempool th = do
     mp <- getMempool
-    setMempool $ filter ((/= th) . blockTxHash) mp
+    setMempool $ filter ((/= th) . txRefHash) mp
 
 insertIntoMempool :: (Monad m, StoreRead m, StoreWrite m) => TxHash -> UnixTime -> m ()
 insertIntoMempool th unixtime = do
     mp <- getMempool
     setMempool . reverse . sort $
-        BlockTx {blockTxBlock = MemRef unixtime, blockTxHash = th} : mp
+        TxRef {txRefBlock = MemRef unixtime, txRefHash = th} : mp
 
+delTx ::
+       ( StoreRead m
+       , StoreWrite m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
+       )
+    => TxHash
+    -> m [TxHash] -- ^ deleted transactions
+delTx th =
+    getTxData th >>= \case
+        Nothing -> do
+            $(logErrorS) "BlockStore" $
+                "Cannot find tx to delete: " <> txHashToHex th
+            throwIO (TxNotFound (txHashToHex th))
+        Just t
+            | txDataDeleted t -> do
+                $(logWarnS) "BlockStore" $
+                    "Already deleted tx: " <> txHashToHex th
+                return []
+            | otherwise -> do
+                accel <- accelTxs [txData t]
+                deleteTx accel True False th
+
 deleteTx ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => Bool -- ^ only delete transaction if unconfirmed
+    => BlockAccel
+    -> Bool -- ^ only delete transaction if unconfirmed
     -> Bool -- ^ do RBF check before deleting transaction
     -> TxHash
     -> m [TxHash] -- ^ deleted transactions
-deleteTx memonly rbfcheck txhash = do
+deleteTx accel memonly rbfcheck txhash = do
     getTxData txhash >>= \case
         Nothing -> do
             $(logErrorS) "BlockStore" $
                 "Cannot find tx to delete: " <> txHashToHex txhash
-            throwError (TxNotFound (txHashToHex txhash))
+            throwIO (TxNotFound (txHashToHex txhash))
         Just t
             | txDataDeleted t -> do
                 $(logWarnS) "BlockStore" $
@@ -430,7 +530,7 @@
             | memonly && confirmed (txDataBlock t) -> do
                 $(logErrorS) "BlockStore" $
                     "Will not delete confirmed tx: " <> txHashToHex txhash
-                throwError (TxConfirmed (txHashToHex txhash))
+                throwIO (TxConfirmed (txHashToHex txhash))
             | rbfcheck ->
                 isRBF (txDataBlock t) (txData t) >>= \case
                     True -> go t
@@ -438,7 +538,7 @@
                         $(logErrorS) "BlockStore" $
                             "Delete non-RBF transaction attempted: " <>
                             txHashToHex txhash
-                        throwError $ CannotDeleteNonRBF (txHashToHex txhash)
+                        throwIO $ CannotDeleteNonRBF (txHashToHex txhash)
             | otherwise -> go t
   where
     go t = do
@@ -452,19 +552,19 @@
                     "Deleting descendant " <> txHashToHex s <>
                     " to delete parent " <>
                     txHashToHex txhash
-                deleteTx True rbfcheck s
+                deleteTx accel True rbfcheck s
         forM_ (take (length (txOut (txData t))) [0 ..]) $ \n ->
-            delOutput (OutPoint txhash n)
+            delOutput accel (OutPoint txhash n)
         let ps = filter (/= nullOutPoint) (map prevOutput (txIn (txData t)))
-        mapM_ unspendOutput ps
+        mapM_ (unspendOutput accel) ps
         unless (confirmed (txDataBlock t)) $ deleteFromMempool txhash
         insertTx t {txDataDeleted = True}
-        updateAddressCounts (txDataAddresses t) (subtract 1)
+        updateAddressCounts accel (txDataAddresses t) (subtract 1)
         return $ nub' (txhash : ths)
 
 
 isRBF ::
-       (StoreRead m, MonadLogger m, MonadError ImportException m)
+       (StoreRead m, MonadLoggerIO m)
     => BlockRef
     -> Tx
     -> m Bool
@@ -487,7 +587,7 @@
                         Nothing -> do
                             $(logErrorS) "BlockStore" $
                                 "Transaction not found: " <> txHashToHex h
-                            throwError (TxNotFound (txHashToHex h))
+                            throwIO (TxNotFound (txHashToHex h))
                         Just t
                             | confirmed (txDataBlock t) -> ck hs'
                             | txDataRBF t -> return True
@@ -497,13 +597,16 @@
 newOutput ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => BlockRef
+    => BlockAccel
+    -> BlockRef
     -> OutPoint
     -> TxOut
     -> m ()
-newOutput br op to = do
+newOutput accel br op to = do
+    delAccelUnspent accel op
     insertUnspent u
     case scriptToAddressBS (scriptOutput to) of
         Left _ -> return ()
@@ -511,8 +614,8 @@
             insertAddrUnspent a u
             insertAddrTx
                 a
-                BlockTx {blockTxHash = outPointHash op, blockTxBlock = br}
-            increaseBalance (confirmed br) True a (outValue to)
+                TxRef {txRefHash = outPointHash op, txRefBlock = br}
+            increaseBalance accel (confirmed br) True a (outValue to)
   where
     u =
         Unspent
@@ -527,12 +630,13 @@
 delOutput ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => OutPoint
+    => BlockAccel
+    -> OutPoint
     -> m ()
-delOutput op = do
+delOutput accel op = do
     t <- getImportTxData (outPointHash op)
     u <-
         case getTxOut (outPointIndex op) (txData t) of
@@ -542,7 +646,8 @@
                     "Output out of range: " <> txHashToHex (txHash (txData t)) <>
                     " " <>
                     fromString (show (outPointIndex op))
-                throwError . OutputOutOfRange . cs $ show op
+                throwIO . OutputOutOfRange . cs $ show op
+    delAccelUnspent accel op
     deleteUnspent op
     case scriptToAddressBS (scriptOutput u) of
         Left _ -> return ()
@@ -559,25 +664,25 @@
                     }
             deleteAddrTx
                 a
-                BlockTx
-                    { blockTxHash = outPointHash op
-                    , blockTxBlock = txDataBlock t
+                TxRef
+                    { txRefHash = outPointHash op
+                    , txRefBlock = txDataBlock t
                     }
-            reduceBalance (confirmed (txDataBlock t)) True a (outValue u)
+            reduceBalance accel (confirmed (txDataBlock t)) True a (outValue u)
 
 getImportTxData ::
-       (StoreRead m, MonadLogger m, MonadError ImportException m)
+       (StoreRead m, MonadLoggerIO m)
     => TxHash
     -> m TxData
 getImportTxData th =
     getTxData th >>= \case
         Nothing -> do
             $(logErrorS) "BlockStore" $ "Tx not found: " <> txHashToHex th
-            throwError $ TxNotFound (txHashToHex th)
+            throwIO $ TxNotFound (txHashToHex th)
         Just d
             | txDataDeleted d -> do
                 $(logErrorS) "BlockStore" $ "Tx deleted: " <> txHashToHex th
-                throwError $ TxDeleted (txHashToHex th)
+                throwIO $ TxDeleted (txHashToHex th)
             | otherwise -> return d
 
 getTxOut
@@ -591,44 +696,48 @@
 spendOutput ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => BlockRef
+    => BlockAccel
+    -> BlockRef
     -> TxHash
     -> Word32
     -> Unspent
     -> m ()
-spendOutput br th ix u = do
+spendOutput accel br th ix u = do
     insertSpender (unspentPoint u) Spender {spenderHash = th, spenderIndex = ix}
     case scriptToAddressBS (B.Short.fromShort (unspentScript u)) of
         Left _ -> return ()
         Right a -> do
             reduceBalance
+                accel
                 (confirmed (unspentBlock u))
                 False
                 a
                 (unspentAmount u)
             deleteAddrUnspent a u
-            insertAddrTx a BlockTx {blockTxHash = th, blockTxBlock = br}
+            insertAddrTx a TxRef {txRefHash = th, txRefBlock = br}
+    delAccelUnspent accel (unspentPoint u)
     deleteUnspent (unspentPoint u)
 
 unspendOutput ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => OutPoint
+    => BlockAccel
+    -> OutPoint
     -> m ()
-unspendOutput op = do
+unspendOutput accel op = do
     t <- getImportTxData (outPointHash op)
     o <-
         case getTxOut (outPointIndex op) (txData t) of
             Nothing -> do
                 $(logErrorS) "BlockStore" $
                     "Output out of range: " <> cs (show op)
-                throwError (OutputOutOfRange (cs (show op)))
+                throwIO (OutputOutOfRange (cs (show op)))
             Just o -> return o
     s <-
         getSpender op >>= \case
@@ -637,7 +746,7 @@
                     "Output already unspent: " <> txHashToHex (outPointHash op) <>
                     " " <>
                     fromString (show (outPointIndex op))
-                throwError (AlreadyUnspent (cs (show op)))
+                throwIO (AlreadyUnspent (cs (show op)))
             Just s -> return s
     x <- getImportTxData (spenderHash s)
     deleteSpender op
@@ -650,6 +759,7 @@
                 , unspentPoint = op
                 , unspentAddress = m
                 }
+    delAccelUnspent accel op
     insertUnspent u
     case m of
         Nothing -> return ()
@@ -657,9 +767,10 @@
             insertAddrUnspent a u
             deleteAddrTx
                 a
-                BlockTx
-                    {blockTxHash = spenderHash s, blockTxBlock = txDataBlock x}
+                TxRef
+                    {txRefHash = spenderHash s, txRefBlock = txDataBlock x}
             increaseBalance
+                accel
                 (confirmed (unspentBlock u))
                 False
                 a
@@ -668,22 +779,23 @@
 reduceBalance ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
-       , MonadError ImportException m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => Bool -- ^ spend or delete confirmed output
+    => BlockAccel
+    -> Bool -- ^ spend or delete confirmed output
     -> Bool -- ^ reduce total received
     -> Address
     -> Word64
     -> m ()
-reduceBalance c t a v = do
+reduceBalance accel c t a v = do
     net <- getNetwork
-    b <- getBalance a
+    b <- getAccelBalance accel a
     if nullBalance b
         then do
             $(logErrorS) "BlockStore" $
                 "Address balance not found: " <> addrText net a
-            throwError (BalanceNotFound (addrText net a))
+            throwIO (BalanceNotFound (addrText net a))
         else do
             when (v > amnt b) $ do
                 $(logErrorS) "BlockStore" $
@@ -693,10 +805,11 @@
                     ", has: " <>
                     cs (show (amnt b)) <>
                     ")"
-                throwError $
+                throwIO $
                     if c
                         then InsufficientBalance (addrText net a)
                         else InsufficientZeroBalance (addrText net a)
+            delAccelBalance accel a
             setBalance
                 b
                     { balanceAmount =
@@ -729,15 +842,18 @@
 increaseBalance ::
        ( StoreRead m
        , StoreWrite m
-       , MonadLogger m
+       , MonadLoggerIO m
+       , MonadUnliftIO m
        )
-    => Bool -- ^ add confirmed output
+    => BlockAccel
+    -> Bool -- ^ add confirmed output
     -> Bool -- ^ increase total received
     -> Address
     -> Word64
     -> m ()
-increaseBalance c t a v = do
-    b <- getBalance a
+increaseBalance accel c t a v = do
+    b <- getAccelBalance accel a
+    delAccelBalance accel a
     setBalance
         b
             { balanceAmount =
@@ -759,18 +875,23 @@
             }
 
 updateAddressCounts ::
-       (StoreWrite m, StoreRead m, Monad m, MonadError ImportException m)
-    => [Address]
+       ( StoreWrite m
+       , StoreRead m
+       , MonadUnliftIO m
+       )
+    => BlockAccel
+    -> [Address]
     -> (Word64 -> Word64)
     -> m ()
-updateAddressCounts as f =
+updateAddressCounts accel as f =
     forM_ as $ \a -> do
         b <-
             do net <- getNetwork
-               b <- getBalance a
+               b <- getAccelBalance accel a
                if nullBalance b
-                   then throwError (BalanceNotFound (addrText net a))
+                   then throwIO (BalanceNotFound (addrText net a))
                    else return b
+        delAccelBalance accel a
         setBalance b {balanceTxCount = f (balanceTxCount b)}
 
 txDataAddresses :: TxData -> [Address]
diff --git a/src/Haskoin/Store/Web.hs b/src/Haskoin/Store/Web.hs
--- a/src/Haskoin/Store/Web.hs
+++ b/src/Haskoin/Store/Web.hs
@@ -66,7 +66,7 @@
                                                 StoreRead (..), blockAtOrBefore,
                                                 getTransaction, nub')
 import           Haskoin.Store.Data            (BlockData (..), BlockRef (..),
-                                                BlockTx (..), DeriveType (..),
+                                                TxRef (..), DeriveType (..),
                                                 Event (..), Except (..),
                                                 GenericResult (..),
                                                 HealthCheck (..),
@@ -410,7 +410,7 @@
 scottyMempool = do
     setHeaders
     proto <- setupBin
-    txs <- map blockTxHash <$> getMempool
+    txs <- map txRefHash <$> getMempool
     protoSerial proto txs
 
 scottyTransaction :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()
@@ -573,7 +573,7 @@
         then do
             txs' <-
                 fmap catMaybes . lift . runNoCache nocache $
-                mapM (getTransaction . blockTxHash) txs
+                mapM (getTransaction . txRefHash) txs
             protoSerialNet proto (list . transactionToEncoding) txs'
         else protoSerial proto txs
 
@@ -958,7 +958,7 @@
         return $ compute_delta bt tm
     tx_time_delta tm bd ml = do
         bd' <- bd
-        tt <- memRefTime . blockTxBlock <$> ml <|> bd
+        tt <- memRefTime . txRefBlock <$> ml <|> bd
         return $ min (compute_delta tt tm) bd'
     timeout_ok to td = fromMaybe False $ do
         td' <- td
@@ -1039,7 +1039,7 @@
        (Monad m, StoreRead m)
     => Limits
     -> Address
-    -> m [BlockTx]
+    -> m [TxRef]
 getAddressTxsLimit limits addr = getAddressTxs addr limits
 
 getAddressTxsFull ::
@@ -1049,13 +1049,13 @@
     -> m [Transaction]
 getAddressTxsFull limits addr = do
     txs <- getAddressTxsLimit limits addr
-    catMaybes <$> mapM (getTransaction . blockTxHash) txs
+    catMaybes <$> mapM (getTransaction . txRefHash) txs
 
 getAddressesTxsLimit ::
        (Monad m, StoreRead m)
     => Limits
     -> [Address]
-    -> m [BlockTx]
+    -> m [TxRef]
 getAddressesTxsLimit limits addrs = getAddressesTxs addrs limits
 
 getAddressesTxsFull ::
@@ -1066,7 +1066,7 @@
 getAddressesTxsFull limits addrs =
     fmap catMaybes $
     getAddressesTxsLimit limits addrs >>=
-    mapM (getTransaction . blockTxHash)
+    mapM (getTransaction . txRefHash)
 
 getAddressUnspentsLimit ::
        (Monad m, StoreRead m)
diff --git a/test/Haskoin/StoreSpec.hs b/test/Haskoin/StoreSpec.hs
--- a/test/Haskoin/StoreSpec.hs
+++ b/test/Haskoin/StoreSpec.hs
@@ -7,7 +7,6 @@
 import           Conduit
 import           Control.Monad
 import           Control.Monad.Logger
-import           Control.Monad.Trans
 import           Data.ByteString        (ByteString)
 import qualified Data.ByteString        as B
 import           Data.ByteString.Base64
@@ -19,7 +18,6 @@
 import           Haskoin
 import           Haskoin.Node
 import           Haskoin.Store
-import           Haskoin.Store.Common
 import           Network.Socket
 import           NQE
 import           System.Random
@@ -117,7 +115,7 @@
     fromRight (error "Could not decode blocks") $
     runGet f (decodeBase64Lenient allBlocksBase64)
   where
-    f = mapM (const get) [1..15]
+    f = mapM (const get) [(1 :: Int) .. 15]
 
 allBlocksBase64 :: ByteString
 allBlocksBase64 =
@@ -193,7 +191,7 @@
             forever (receive r >>= yield) .| inc .| concatMapC mockPeerReact .|
             outc .|
             awaitForever (`send` s)
-    outc = mapMC $ \msg -> return $ runPut (putMessage net msg)
+    outc = mapMC $ \msg' -> return $ runPut (putMessage net msg')
     inc =
         forever $ do
             x <- takeCE 24 .| foldC
@@ -205,7 +203,7 @@
                         Left e ->
                             error $
                             "Dummy peer could not decode payload: " <> show e
-                        Right msg -> yield msg
+                        Right msg' -> yield msg'
 
 mockPeerReact :: Message -> [Message]
 mockPeerReact (MPing (Ping n)) = [MPong (Pong n)]
