haskoin-store 0.43.1 → 0.44.0
raw patch · 8 files changed
+87/−24 lines, 8 filesdep ~haskoin-store-dataPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: haskoin-store-data
API changes (from Hackage documentation)
+ Haskoin.Store: getNumTxData :: StoreReadExtra m => Word64 -> m (Maybe TxData)
+ Haskoin.Store.Common: getNumTransaction :: (Monad m, StoreReadExtra m) => Word64 -> m (Maybe Transaction)
+ Haskoin.Store.Common: getNumTxData :: StoreReadExtra m => Word64 -> m (Maybe TxData)
+ Haskoin.Store.Database.Types: TxKeyS :: (Word32, Word16) -> TxKey
+ Haskoin.Store.Database.Types: [txKeyShort] :: TxKey -> (Word32, Word16)
+ Haskoin.Store.Database.Types: decodeTxKey :: Word64 -> ((Word32, Word16), Word8)
Files
- CHANGELOG.md +4/−0
- haskoin-store.cabal +5/−5
- src/Haskoin/Store/BlockStore.hs +2/−0
- src/Haskoin/Store/Cache.hs +1/−0
- src/Haskoin/Store/Common.hs +13/−4
- src/Haskoin/Store/Database/Reader.hs +28/−7
- src/Haskoin/Store/Database/Types.hs +23/−2
- src/Haskoin/Store/Web.hs +11/−6
CHANGELOG.md view
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html) +## 0.44.0+### Changed+- Numeric txid now 53 bits long and doesn't return transactions when hashes collide.+ ## 0.43.1 ### Fixed - Do not overcount statistics.
haskoin-store.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 983e918209925f2ad39689718c9bc45e2a911b06e1154238a04664b41899aa89+-- hash: b5a848bca1fcc3e0b0c69c2b9e0b04b81a35c40cf454e1e03fd93e3aa3679d6a name: haskoin-store-version: 0.43.1+version: 0.44.0 synopsis: Storage and index for Bitcoin and Bitcoin Cash description: Please see the README on GitHub at <https://github.com/haskoin/haskoin-store#readme> category: Bitcoin, Finance, Network@@ -59,7 +59,7 @@ , hashable >=1.3.0.0 , haskoin-core >=0.19.0 , haskoin-node >=0.17.0- , haskoin-store-data ==0.43.0+ , haskoin-store-data ==0.44.0 , hedis >=0.12.13 , http-types >=0.12.3 , lens >=4.18.1@@ -109,7 +109,7 @@ , haskoin-core >=0.19.0 , haskoin-node >=0.17.0 , haskoin-store- , haskoin-store-data ==0.43.0+ , haskoin-store-data ==0.44.0 , hedis >=0.12.13 , http-types >=0.12.3 , lens >=4.18.1@@ -164,7 +164,7 @@ , haskoin-core >=0.19.0 , haskoin-node >=0.17.0 , haskoin-store- , haskoin-store-data ==0.43.0+ , haskoin-store-data ==0.44.0 , hedis >=0.12.13 , hspec >=2.7.1 , http-types >=0.12.3
src/Haskoin/Store/BlockStore.hs view
@@ -273,6 +273,8 @@ runRocksDB . getAddressUnspents a getAddressTxs a = runRocksDB . getAddressTxs a+ getNumTxData =+ runRocksDB . getNumTxData -- | Run block store process. withBlockStore ::
src/Haskoin/Store/Cache.hs view
@@ -225,6 +225,7 @@ Just cfg -> lift (runReaderT (getXPubTxs xpub limits) cfg) getMaxGap = lift getMaxGap getInitialGap = lift getInitialGap+ getNumTxData = lift . getNumTxData withCache :: StoreReadBase m => Maybe CacheConfig -> CacheT m a -> m a withCache s f = runReaderT f s
src/Haskoin/Store/Common.hs view
@@ -21,6 +21,7 @@ , xPubBalsTxs , xPubBalsUnspents , getTransaction+ , getNumTransaction , blockAtOrBefore , blockAtOrAfterMTP , deOffset@@ -40,8 +41,8 @@ import Data.ByteString (ByteString) import Data.Default (Default (..)) import Data.Function (on)-import Data.Hashable (Hashable) import qualified Data.HashSet as H+import Data.Hashable (Hashable) import Data.IntMap.Strict (IntMap) import qualified Data.IntMap.Strict as I import Data.List (sortBy)@@ -66,7 +67,7 @@ import Haskoin.Node (Chain, Peer) import Haskoin.Store.Data (Balance (..), BlockData (..), DeriveType (..), Spender,- Transaction, TxData (..),+ Transaction (..), TxData (..), TxRef (..), UnixTime, Unspent (..), XPubBal (..), XPubSpec (..), XPubSummary (..), XPubUnspent (..),@@ -124,6 +125,7 @@ getAddressUnspents :: Address -> Limits -> m [Unspent] getAddressUnspents a = getAddressesUnspents [a] getAddressesUnspents :: [Address] -> Limits -> m [Unspent]+ getNumTxData :: Word64 -> m (Maybe TxData) xPubBals :: XPubSpec -> m [XPubBal] xPubBals xpub = do igap <- getInitialGap@@ -220,12 +222,12 @@ getActiveBlock :: StoreReadExtra m => BlockHash -> m (Maybe BlockData) getActiveBlock bh = getBlock bh >>= \case Just b | blockDataMainChain b -> return (Just b)- _ -> return Nothing+ _ -> return Nothing getActiveTxData :: StoreReadBase m => TxHash -> m (Maybe TxData) getActiveTxData th = getTxData th >>= \case Just td | not (txDataDeleted td) -> return (Just td)- _ -> return Nothing+ _ -> return Nothing getDefaultBalance :: StoreReadBase m => Address -> m Balance getDefaultBalance a = getBalance a >>= \case@@ -275,6 +277,13 @@ getTransaction h = runMaybeT $ do d <- MaybeT $ getTxData h sm <- lift $ getSpenders h+ return $ toTransaction d sm++getNumTransaction ::+ (Monad m, StoreReadExtra m) => Word64 -> m (Maybe Transaction)+getNumTransaction i = runMaybeT $ do+ d <- MaybeT $ getNumTxData i+ sm <- lift $ getSpenders (txHash (txData d)) return $ toTransaction d sm blockAtOrBefore :: (MonadIO m, StoreReadExtra m)
src/Haskoin/Store/Database/Reader.hs view
@@ -16,20 +16,26 @@ , balanceCF ) where -import Conduit (mapC, runConduit, sinkList, (.|))+import Conduit (lift, mapC, runConduit, sinkList,+ (.|)) import Control.Monad.Except (runExceptT, throwError) import Control.Monad.Reader (ReaderT, ask, asks, runReaderT)+import Data.Bits ((.&.))+import qualified Data.ByteString as BS import Data.Default (def) import Data.Function (on) import Data.List (sortBy) import Data.Maybe (fromMaybe)-import Data.Word (Word32)+import Data.Serialize (encode)+import Data.Word (Word32, Word64) import Database.RocksDB (ColumnFamily, Config (..), DB (..), withDBCF, withIterCF)-import Database.RocksDB.Query (insert, matching, matchingSkip,+import Database.RocksDB.Query (insert, matching,+ matchingAsListCF, matchingSkip, retrieve, retrieveCF) import Haskoin (Address, BlockHash, BlockHeight,- Network, OutPoint (..), TxHash)+ Network, OutPoint (..), TxHash,+ txHash) import Haskoin.Store.Common import Haskoin.Store.Data import Haskoin.Store.Database.Types@@ -139,6 +145,19 @@ getTxDataDB th DatabaseReader{databaseHandle = db} = retrieveCF db (txCF db) (TxKey th) +getNumTxDataDB :: MonadIO m => Word64 -> DatabaseReader -> m (Maybe TxData)+getNumTxDataDB i r@DatabaseReader{databaseHandle = db} = do+ let (sk, w) = decodeTxKey i+ ls <- liftIO $ matchingAsListCF db (txCF db) (TxKeyS sk)+ let f t = let bs = encode $ txHash (txData t)+ b = BS.head (BS.drop 6 bs)+ w' = b .&. 0xf8+ in w == w'+ xs = filter f $ map snd ls+ case xs of+ [x] -> return $ Just x+ _ -> return Nothing+ getSpenderDB :: MonadIO m => OutPoint -> DatabaseReader -> m (Maybe Spender) getSpenderDB op DatabaseReader{databaseHandle = db} = retrieveCF db (spenderCF db) $ SpenderKey op@@ -176,7 +195,7 @@ case start limits of Nothing -> matching it (AddrTxKeyA a) Just (AtTx txh) ->- getTxDataDB txh bdb >>= \case+ lift (getTxDataDB txh bdb) >>= \case Just TxData {txDataBlock = b@BlockRef {}} -> matchingSkip it (AddrTxKeyA a) (AddrTxKeyB a b) _ -> matching it (AddrTxKeyA a)@@ -216,14 +235,15 @@ x it .| applyLimitsC limits .| mapC (uncurry toUnspent) .| sinkList where x it = case start limits of- Nothing -> matching it (AddrOutKeyA a)+ Nothing ->+ matching it (AddrOutKeyA a) Just (AtBlock h) -> matchingSkip it (AddrOutKeyA a) (AddrOutKeyB a (BlockRef h maxBound)) Just (AtTx txh) ->- getTxDataDB txh bdb >>= \case+ lift (getTxDataDB txh bdb) >>= \case Just TxData {txDataBlock = b@BlockRef {}} -> matchingSkip it (AddrOutKeyA a) (AddrOutKeyB a b) _ -> matching it (AddrOutKeyA a)@@ -246,3 +266,4 @@ getAddressTxs a limits = ask >>= getAddressTxsDB a limits getMaxGap = asks databaseMaxGap getInitialGap = asks databaseInitialGap+ getNumTxData t = ask >>= getNumTxDataDB t
src/Haskoin/Store/Database/Types.hs view
@@ -12,6 +12,7 @@ , MemKey(..) , SpenderKey(..) , TxKey(..)+ , decodeTxKey , UnspentKey(..) , VersionKey(..) , BalVal(..)@@ -26,7 +27,8 @@ import Control.DeepSeq (NFData) import Control.Monad (guard)-import Data.Bits (Bits, shiftL, shiftR, (.|.))+import Data.Bits (Bits, shift, shiftL, shiftR, (.&.),+ (.|.)) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import Data.ByteString.Short (ShortByteString)@@ -35,7 +37,9 @@ import Data.Either (fromRight) import Data.Hashable (Hashable) import Data.Serialize (Serialize (..), decode, encode,- getBytes, getWord8, putWord8, runPut)+ getBytes, getWord16be, getWord32be,+ getWord8, putWord32be, putWord64be,+ putWord8, runGet, runPut) import Data.Word (Word16, Word32, Word64, Word8) import Database.RocksDB.Query (Key, KeyValue) import GHC.Generics (Generic)@@ -137,6 +141,7 @@ -- | Transaction database key. data TxKey = TxKey { txKey :: TxHash }+ | TxKeyS { txKeyShort :: (Word32, Word16) } deriving (Show, Read, Eq, Ord, Generic, Hashable) instance Serialize TxKey where@@ -144,9 +149,25 @@ put (TxKey h) = do putWord8 0x02 put h+ put (TxKeyS h) = do+ putWord8 0x02+ put h get = do guard . (== 0x02) =<< getWord8 TxKey <$> get++decodeTxKey :: Word64 -> ((Word32, Word16), Word8)+decodeTxKey i =+ let masked = i .&. 0x001fffffffffffff+ wb = masked `shift` 11+ bs = runPut (putWord64be wb)+ g = do+ w1 <- getWord32be+ w2 <- getWord16be+ w3 <- getWord8+ return (w1, w2, w3)+ Right (w1, w2, w3) = runGet g bs+ in ((w1, w2), w3) instance Key TxKey instance KeyValue TxKey TxData
src/Haskoin/Store/Web.hs view
@@ -316,6 +316,7 @@ xPubSummary = runInWebReader . xPubSummary xPubUnspents xpub = runInWebReader . xPubUnspents xpub xPubTxs xpub = runInWebReader . xPubTxs xpub+ getNumTxData = runInWebReader . getNumTxData instance (MonadUnliftIO m, MonadLoggerIO m) => StoreReadBase (WebT m) where getNetwork = lift getNetwork@@ -338,6 +339,7 @@ xPubTxs xpub = lift . xPubTxs xpub getMaxGap = lift getMaxGap getInitialGap = lift getInitialGap+ getNumTxData = lift . getNumTxData ------------------- -- Path Handlers --@@ -1518,7 +1520,7 @@ scottyBinfoTx = lift (asks (webNumTxId . webConfig)) >>= \numtxid -> S.param "txid" >>= \txid ->- withMetrics rawtxResponseTime 1 $ go numtxid (decodeBinfoTxId txid)+ withMetrics rawtxResponseTime 1 $ go numtxid txid where get_format = S.param "format" `S.rescue` const (return ("json" :: Text)) js numtxid t = do@@ -1528,11 +1530,14 @@ hex t = do setHeaders S.text . TL.fromStrict . encodeHex . encode $ transactionData t- go numtxid h = getTransaction h >>= \case- Nothing -> raise rawtxErrors ThingNotFound- Just t -> get_format >>= \case- "hex" -> hex t- _ -> js numtxid t+ go numtxid txid =+ let f (BinfoTxIdHash h) = getTransaction h+ f (BinfoTxIdIndex i) = getNumTransaction i+ in f txid >>= \case+ Nothing -> raise rawtxErrors ThingNotFound+ Just t -> get_format >>= \case+ "hex" -> hex t+ _ -> js numtxid t -- GET Network Information --