packages feed

haskoin-store 0.53.2 → 0.53.3

raw patch · 4 files changed

+112/−22 lines, 4 filesdep ~haskoin-coredep ~haskoin-store-dataPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: haskoin-core, haskoin-store-data

API changes (from Hackage documentation)

+ Haskoin.Store.Web: [maxLimitBody] :: WebLimits -> !Word32
- Haskoin.Store.Web: WebLimits :: !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> WebLimits
+ Haskoin.Store.Web: WebLimits :: !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> WebLimits

Files

CHANGELOG.md view
@@ -4,6 +4,13 @@ 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.53.3+### Added+- Blockchain.info endpoint: `q/pubkeyhash/:addr`.+- Blockchain.info endpoint: `q/getsentbyaddress/:addr`.+- Blockchain.info endpoint: `q/pubkeyaddr/:addr`.+- Configurable request body limit size.+ ## 0.53.2 ### Fixed - Return output in satoshi for some endpoints.
app/Main.hs view
@@ -198,12 +198,14 @@     def_limit  <- defEnv "DEF_LIMIT" (maxLimitDefault def) readMaybe     max_gap    <- defEnv "MAX_GAP" (maxLimitGap def) readMaybe     init_gap   <- defEnv "INIT_GAP" (maxLimitInitialGap def) readMaybe+    max_body   <- defEnv "MAX_BODY" (maxLimitBody def) readMaybe     return WebLimits { maxLimitCount = max_limit                      , maxLimitFull = max_full                      , maxLimitOffset = max_offset                      , maxLimitDefault = def_limit                      , maxLimitGap = max_gap                      , maxLimitInitialGap = init_gap+                     , maxLimitBody = max_body                      } {-# NOINLINE defWebLimits #-} @@ -409,6 +411,13 @@         <> help "Max gap for empty xpub"         <> showDefault         <> value (maxLimitInitialGap (configWebLimits def))+    maxLimitBody <-+        option auto $+        metavar "BYTES"+        <> long "max-body"+        <> help "Maximum request body size"+        <> showDefault+        <> value (maxLimitBody (configWebLimits def))     blockTimeout <-         option auto $         metavar "SECONDS"
haskoin-store.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 7f0440e3b9697fe1c6eead20f4f9dad0b4795c894bbd89689d0049b68916587d+-- hash: b3b7762ba16d37c51367999ec82a9bf98fde10493c5fa48171a6a05ca6e94d45  name:           haskoin-store-version:        0.53.2+version:        0.53.3 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@@ -60,9 +60,9 @@     , ekg-statsd >=0.2.5     , foldl >=1.4.10     , hashable >=1.3.0.0-    , haskoin-core >=0.19.0+    , haskoin-core >=0.20.4     , haskoin-node >=0.17.0-    , haskoin-store-data ==0.53.2+    , haskoin-store-data ==0.53.3     , hedis >=0.12.13     , http-types >=0.12.3     , lens >=4.18.1@@ -113,10 +113,10 @@     , filepath     , foldl >=1.4.10     , hashable >=1.3.0.0-    , haskoin-core >=0.19.0+    , haskoin-core >=0.20.4     , haskoin-node >=0.17.0     , haskoin-store-    , haskoin-store-data ==0.53.2+    , haskoin-store-data ==0.53.3     , hedis >=0.12.13     , http-types >=0.12.3     , lens >=4.18.1@@ -172,10 +172,10 @@     , ekg-statsd >=0.2.5     , foldl >=1.4.10     , hashable >=1.3.0.0-    , haskoin-core >=0.19.0+    , haskoin-core >=0.20.4     , haskoin-node >=0.17.0     , haskoin-store-    , haskoin-store-data ==0.53.2+    , haskoin-store-data ==0.53.3     , hedis >=0.12.13     , hspec >=2.7.1     , http-types >=0.12.3
src/Haskoin/Store/Web.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleInstances   #-} {-# LANGUAGE LambdaCase          #-} {-# LANGUAGE MultiWayIf          #-}+{-# LANGUAGE NamedFieldPuns      #-} {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE RecordWildCards     #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -19,11 +20,13 @@     ) where  import           Conduit                                 (ConduitT, await,+                                                          concatMapC,                                                           concatMapMC, dropC,-                                                          dropWhileC, mapC,-                                                          runConduit, sinkList,-                                                          takeC, takeWhileC,-                                                          yield, (.|))+                                                          dropWhileC, headC,+                                                          mapC, runConduit,+                                                          sinkList, takeC,+                                                          takeWhileC, yield,+                                                          (.|)) import           Control.Applicative                     ((<|>)) import           Control.Arrow                           (second) import           Control.Lens                            ((.~), (^.))@@ -69,6 +72,7 @@                                                           fromMaybe, isJust,                                                           mapMaybe, maybeToList) import           Data.Proxy                              (Proxy (..))+import           Data.Serialize                          (decode) import           Data.String                             (fromString) import           Data.String.Conversions                 (cs) import           Data.Text                               (Text)@@ -95,6 +99,7 @@                                                           chainGetAncestor,                                                           chainGetBest,                                                           getPeers, sendMessage)+import           Haskoin.Script import           Haskoin.Store.BlockStore import           Haskoin.Store.Cache import           Haskoin.Store.Common@@ -152,6 +157,7 @@     , maxLimitDefault    :: !Word32     , maxLimitGap        :: !Word32     , maxLimitInitialGap :: !Word32+    , maxLimitBody       :: !Word32     }     deriving (Eq, Show) @@ -164,6 +170,7 @@             , maxLimitDefault = 100             , maxLimitGap = 32             , maxLimitInitialGap = 20+            , maxLimitBody = 1024 * 1024             }  data WebConfig = WebConfig@@ -358,6 +365,7 @@                     , webStore = store'                     , webStats = stats                     , webPriceGet = pget+                    , webMaxLimits = WebLimits{..}                     } = do     ticker <- newTVarIO HashMap.empty     metrics <- mapM createMetrics stats@@ -372,7 +380,7 @@         runner <- askRunInIO         S.scottyOptsT opts (runner . (`runReaderT` st)) $ do             S.middleware reqLogger-            S.middleware reqSizeLimit+            S.middleware (reqSizeLimit maxLimitBody)             S.defaultHandler defHandler             handlePaths             S.notFound $ raise_ ThingNotFound@@ -678,7 +686,9 @@     S.get  "/blockchain/export-history" scottyBinfoHistory     S.post "/blockchain/export-history" scottyBinfoHistory     S.get  "/blockchain/q/addresstohash/:addr"  scottyBinfoAddrToHash+    S.get  "/blockchain/q/hashtoaddress/:hash" scottyBinfoHashToAddr     S.get  "/blockchain/q/addrpubkey/:pubkey"  scottyBinfoAddrPubkey+    S.get  "/blockchain/q/pubkeyaddr/:addr" scottyBinfoPubKeyAddr     S.get  "/blockchain/q/hashpubkey/:pubkey"  scottyBinfoHashPubkey     S.get  "/blockchain/q/getblockcount" scottyBinfoGetBlockCount     S.get  "/blockchain/q/latesthash" scottyBinfoLatestHash@@ -688,6 +698,7 @@     S.get  "/blockchain/q/txfee/:txid" scottyBinfoTxFees     S.get  "/blockchain/q/txresult/:txid/:addr" scottyBinfoTxResult     S.get  "/blockchain/q/getreceivedbyaddress/:addr" scottyBinfoReceived+    S.get  "/blockchain/q/getsentbyaddress/:addr" scottyBinfoSent     S.get  "/blockchain/q/addressbalance/:addr" scottyBinfoAddrBalance     S.get  "/blockchain/q/addressfirstseen/:addr" scottyFirstSeen   where@@ -1853,6 +1864,14 @@     setHeaders     S.text . cs . show $ balanceTotalReceived b +scottyBinfoSent :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()+scottyBinfoSent = do+    setMetrics addrBalanceStat 1+    a <- getAddress "addr"+    b <- fromMaybe (zeroBalance a) <$> getBalance a+    setHeaders+    S.text . cs . show $ balanceTotalReceived b - balanceAmount b - balanceZero b+ scottyBinfoAddrBalance :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m () scottyBinfoAddrBalance = do     setMetrics addrBalanceStat 1@@ -2164,23 +2183,78 @@         H.computeSubsidy net (H.nodeHeight bn + 1)  scottyBinfoAddrToHash :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()-scottyBinfoAddrToHash =-    getAddress "addr" >>= \addr -> do+scottyBinfoAddrToHash = do+    addr <- getAddress "addr"     setHeaders     S.text . encodeHexLazy . runPutL . serialize $ getAddrHash160 addr +scottyBinfoHashToAddr :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()+scottyBinfoHashToAddr = do+    bs <- maybe S.next return . decodeHex =<< S.param "hash"+    net <- asks (storeNetwork . webStore . webConfig)+    hash <- either (const S.next) return (decode bs)+    addr <- maybe S.next return (addrToText net (PubKeyAddress hash))+    setHeaders+    S.text $ TL.fromStrict addr+ scottyBinfoAddrPubkey :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m () scottyBinfoAddrPubkey = do-  pubkey <- pubKeyAddr . fromString <$> S.param "pubkey"+  hex <- S.param "pubkey"+  pubkey <- maybe S.next (return . pubKeyAddr) $+      eitherToMaybe . runGetS deserialize =<< decodeHex hex   net <- lift $ asks (storeNetwork . webStore . webConfig)   setHeaders   case addrToText net pubkey of-    Nothing -> raise rawaddrStat ThingNotFound-    Just a  -> S.text $ TL.fromStrict a+      Nothing -> raise rawaddrStat ThingNotFound+      Just a  -> S.text $ TL.fromStrict a +scottyBinfoPubKeyAddr :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m ()+scottyBinfoPubKeyAddr = do+    addr <- getAddress "addr"+    mi <- strm addr+    i <- case mi of+        Nothing -> raise_ ThingNotFound+        Just i  -> return i+    pk <- case extr addr i of+        Left e  -> raise_ $ UserError e+        Right t -> return t+    setHeaders+    S.text $ encodeHexLazy $ L.fromStrict pk+  where+    strm addr = runConduit $+        streamThings (getAddressTxs addr) (Just txRefHash) def{limit = 50} .|+        concatMapMC (getTransaction . txRefHash) .|+        concatMapC (filter (inp addr) . transactionInputs) .|+        headC+    inp addr StoreInput{inputAddress = Just a} = a == addr+    inp _ _                                    = False+    extr addr StoreInput{inputSigScript, inputPkScript, inputWitness} = do+        Script sig <- decode inputSigScript+        Script pks <- decode inputPkScript+        case addr of+            PubKeyAddress{} ->+                case sig of+                    [OP_PUSHDATA _ _, OP_PUSHDATA pub _] ->+                        Right pub+                    [OP_PUSHDATA _ _] ->+                        case pks of+                            [OP_PUSHDATA pub _, OP_CHECKSIG] ->+                                Right pub+                            _ -> Left "Could not parse scriptPubKey"+                    _ -> Left "Could not parse scriptSig"+            WitnessPubKeyAddress{} ->+                case inputWitness of+                    [_, pub] -> return pub+                    _        -> Left "Could not parse scriptPubKey"+            _ -> Left "Address does not have public key"+    extr _ _ = Left "Incorrect input type"+ scottyBinfoHashPubkey :: (MonadUnliftIO m, MonadLoggerIO m) => WebT m () scottyBinfoHashPubkey = do-  addr <- pubKeyAddr . fromString <$> S.param "pubkey"+  pkm <- (eitherToMaybe . runGetS deserialize <=< decodeHex) <$> S.param "pubkey"+  addr <- case pkm of+      Nothing -> raise_ $ UserError "Could not decode public key"+      Just pk -> return $ pubKeyAddr pk   setHeaders   S.text . encodeHexLazy . runPutL . serialize $ getAddrHash160 addr @@ -2497,10 +2571,10 @@             runner $ $(logWarnS) "Web" $                 "Slow [" <> cs (show diff) <> " ms]: " <> fmtReq b req -reqSizeLimit :: Middleware-reqSizeLimit = requestSizeLimitMiddleware lim+reqSizeLimit :: Integral i => i -> Middleware+reqSizeLimit i = requestSizeLimitMiddleware lim   where-    max_len _req = return (Just (256 * 1024))+    max_len _req = return (Just (fromIntegral i))     lim = setOnLengthExceeded too_big $           setMaxLengthForRequest max_len           defaultRequestSizeLimitSettings