diff --git a/CHANGELOG.md b/CHANGELOG.md index 87f20e8..71bf4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.1.0.0 -- 2024-08-27 +## [0.2.0.0] -- 2024-10-11 + +### Added + +- `getblockinfo` endpoint +- `cabal.project.freeze` file + +### Changed + +- Zcash-Haskell update to 0.7.1.1 + +## [0.1.0.0] -- 2024-08-27 * First version. Released on an unsuspecting world. diff --git a/cabal.project b/cabal.project index a05e201..aaab33d 100644 --- a/cabal.project +++ b/cabal.project @@ -7,7 +7,7 @@ with-compiler: ghc-9.6.5 source-repository-package type: git location: https://git.vergara.tech/Vergara_Tech/haskell-hexstring.git - tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7 + tag: 0.12.2.0 source-repository-package type: git diff --git a/cabal.project.freeze b/cabal.project.freeze new file mode 100644 index 0000000..5c4dd0c --- /dev/null +++ b/cabal.project.freeze @@ -0,0 +1,262 @@ +active-repositories: hackage.haskell.org:merge +constraints: any.Cabal ==3.10.3.0, + any.Cabal-syntax ==3.10.3.0, + any.HUnit ==1.6.2.0, + any.OneTuple ==0.4.2, + any.QuickCheck ==2.14.3, + QuickCheck -old-random +templatehaskell, + any.StateVar ==1.2.2, + any.aeson ==2.2.3.0, + aeson +ordered-keymap, + any.alex ==3.5.1.0, + any.ansi-terminal ==1.1.1, + ansi-terminal -example, + any.ansi-terminal-types ==1.1, + any.appar ==0.1.8, + any.array ==0.5.6.0, + any.asn1-encoding ==0.9.6, + any.asn1-parse ==0.9.5, + any.asn1-types ==0.3.4, + any.assoc ==1.1.1, + assoc -tagged, + any.async ==2.2.5, + async -bench, + any.attoparsec ==0.14.4, + attoparsec -developer, + any.attoparsec-aeson ==2.2.2.0, + any.auto-update ==0.2.1, + any.base ==4.18.2.1, + any.base-compat ==0.14.0, + any.base-orphans ==0.9.2, + any.base16 ==1.0, + any.base16-bytestring ==1.0.2.0, + any.base58-bytestring ==0.1.0, + any.base64-bytestring ==1.2.1.0, + any.basement ==0.0.16, + any.bifunctors ==5.6.2, + bifunctors +tagged, + any.binary ==0.8.9.1, + any.binary-orphans ==1.0.5, + any.bitvec ==1.1.5.0, + bitvec +simd, + any.blaze-builder ==0.4.2.3, + any.blaze-html ==0.9.2.0, + any.blaze-markup ==0.8.3.0, + any.boring ==0.2.2, + boring +tagged, + any.borsh ==0.3.0, + any.bsb-http-chunked ==0.0.0.4, + any.byteorder ==1.0.4, + any.bytes ==0.17.3, + any.bytestring ==0.11.5.3, + any.c2hs ==0.28.8, + c2hs +base3 -regression, + any.call-stack ==0.4.0, + any.case-insensitive ==1.2.1.0, + any.cborg ==0.2.10.0, + cborg +optimize-gmp, + any.cereal ==0.5.8.3, + cereal -bytestring-builder, + any.character-ps ==0.1, + any.colour ==2.3.6, + any.comonad ==5.0.8, + comonad +containers +distributive +indexed-traversable, + any.conduit ==1.3.6, + any.conduit-extra ==1.3.6, + any.constraints ==0.14.2, + any.containers ==0.6.7, + any.contravariant ==1.5.5, + contravariant +semigroups +statevar +tagged, + any.cookie ==0.5.0, + any.crypton ==1.0.0, + crypton -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq +support_pclmuldq +support_rdrand -support_sse +use_target_attributes, + any.crypton-connection ==0.4.1, + any.crypton-x509 ==1.7.7, + any.crypton-x509-store ==1.6.9, + any.crypton-x509-system ==1.6.7, + any.crypton-x509-validation ==1.6.12, + any.cryptonite ==0.30, + cryptonite -check_alignment +integer-gmp -old_toolchain_inliner +support_aesni +support_deepseq -support_pclmuldq +support_rdrand -support_sse +use_target_attributes, + any.data-default ==0.7.1.1, + any.data-default-class ==0.1.2.0, + any.data-default-instances-containers ==0.0.1, + any.data-default-instances-dlist ==0.0.1, + any.data-default-instances-old-locale ==0.0.1, + any.data-fix ==0.3.4, + any.dec ==0.0.6, + any.deepseq ==1.4.8.1, + any.directory ==1.3.8.4, + any.distributive ==0.6.2.1, + distributive +semigroups +tagged, + any.dlist ==1.0, + dlist -werror, + any.easy-file ==0.2.5, + any.entropy ==0.4.1.10, + entropy -donotgetentropy, + any.envy ==2.1.3.0, + any.exceptions ==0.10.7, + any.fast-logger ==3.2.3, + any.file-embed ==0.0.16.0, + any.filepath ==1.4.300.1, + any.foreign-rust ==0.1.0, + any.generically ==0.1.1, + any.generics-sop ==0.5.1.4, + any.ghc-bignum ==1.3, + any.ghc-boot-th ==9.6.5, + any.ghc-prim ==0.10.0, + any.half ==0.3.1, + any.happy ==2.0.2, + any.happy-lib ==2.0.2, + any.hashable ==1.4.7.0, + hashable -arch-native +integer-gmp -random-initial-seed, + any.haskell-lexer ==1.1.1, + any.haskoin-core ==1.1.0, + any.hexstring ==0.12.1.0, + any.hourglass ==0.2.12, + any.hsc2hs ==0.68.10, + hsc2hs -in-ghc-tree, + any.hspec ==2.11.9, + any.hspec-core ==2.11.9, + any.hspec-discover ==2.11.9, + any.hspec-expectations ==0.8.4, + any.http-api-data ==0.6.1, + http-api-data -use-text-show, + any.http-client ==0.7.17, + http-client +network-uri, + any.http-client-tls ==0.3.6.3, + any.http-conduit ==2.3.9, + http-conduit +aeson, + any.http-date ==0.0.11, + any.http-media ==0.8.1.1, + any.http-semantics ==0.2.1, + any.http-types ==0.12.4, + any.http2 ==5.3.4, + http2 -devel -h2spec, + any.indexed-traversable ==0.1.4, + any.indexed-traversable-instances ==0.1.2, + any.integer-conversion ==0.1.1, + any.integer-gmp ==1.1, + any.integer-logarithms ==1.0.3.1, + integer-logarithms -check-bounds +integer-gmp, + any.iproute ==1.7.14, + any.language-c ==0.9.3, + language-c -allwarnings +iecfpextension +usebytestrings, + any.memory ==0.18.0, + memory +support_bytestring +support_deepseq, + any.mime-types ==0.1.2.0, + any.mmorph ==1.2.0, + any.monad-control ==1.0.3.1, + any.mono-traversable ==1.0.20.0, + any.mtl ==2.3.1, + any.murmur3 ==1.0.5, + any.network ==3.2.4.0, + network -devel, + any.network-byte-order ==0.1.7, + any.network-control ==0.1.3, + any.network-uri ==2.6.4.2, + any.old-locale ==1.0.0.7, + any.old-time ==1.1.0.4, + any.optparse-applicative ==0.18.1.0, + optparse-applicative +process, + any.os-string ==2.0.6, + any.parsec ==3.1.16.1, + any.pem ==0.2.4, + any.pretty ==1.1.3.6, + any.prettyprinter ==1.7.1, + prettyprinter -buildreadme +text, + any.prettyprinter-ansi-terminal ==1.1.3, + any.primitive ==0.9.0.0, + any.process ==1.6.19.0, + any.psqueues ==0.2.8.0, + any.quickcheck-io ==0.2.0, + any.quickcheck-transformer ==0.3.1.2, + any.random ==1.2.1.2, + any.recv ==0.1.0, + any.regex-base ==0.94.0.2, + any.regex-compat ==0.95.2.1, + any.regex-posix ==0.96.0.1, + regex-posix -_regex-posix-clib, + any.resourcet ==1.3.0, + any.rts ==1.0.2, + any.safe ==0.3.21, + any.safe-exceptions ==0.1.7.4, + any.scientific ==0.3.8.0, + scientific -integer-simple, + any.secp256k1-haskell ==1.4.0, + any.semialign ==1.3.1, + semialign +semigroupoids, + any.semigroupoids ==6.0.1, + semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers, + any.serialise ==0.2.6.1, + serialise +newtime15, + any.servant ==0.20.2, + any.servant-server ==0.20.2, + any.simple-sendfile ==0.2.32, + simple-sendfile +allow-bsd -fallback, + any.singleton-bool ==0.1.8, + any.socks ==0.6.1, + any.some ==1.0.6, + some +newtype-unsafe, + any.sop-core ==0.5.0.2, + any.split ==0.2.5, + any.splitmix ==0.1.0.5, + splitmix -optimised-mixer, + any.stm ==2.5.1.0, + any.streaming-commons ==0.2.2.6, + streaming-commons -use-bytestring-builder, + any.strict ==0.5.1, + any.string-conversions ==0.4.0.1, + any.tagged ==0.8.8, + tagged +deepseq +transformers, + any.template-haskell ==2.20.0.0, + any.text ==2.0.2, + any.text-iso8601 ==0.1.1, + any.text-short ==0.1.6, + text-short -asserts, + any.tf-random ==0.5, + any.th-abstraction ==0.7.0.0, + any.th-compat ==0.1.5, + any.these ==1.2.1, + any.time ==1.12.2, + any.time-compat ==1.9.7, + any.time-manager ==0.1.0, + any.tls ==2.1.0, + tls -devel, + any.transformers ==0.6.1.0, + any.transformers-base ==0.4.6, + transformers-base +orphaninstances, + any.transformers-compat ==0.7.2, + transformers-compat -five +five-three -four +generic-deriving +mtl -three -two, + any.typed-process ==0.2.12.0, + any.unix ==2.8.4.0, + any.unix-compat ==0.7.2, + any.unix-time ==0.4.15, + any.unliftio ==0.2.25.0, + any.unliftio-core ==0.2.1.0, + any.unordered-containers ==0.2.20, + unordered-containers -debug, + any.utf8-string ==1.0.2, + any.uuid-types ==1.0.6, + any.vault ==0.3.1.5, + vault +useghc, + any.vector ==0.13.1.0, + vector +boundschecks -internalchecks -unsafechecks -wall, + any.vector-algorithms ==0.9.0.2, + vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks, + any.vector-stream ==0.1.0.1, + any.void ==0.7.3, + void -safe, + any.wai ==3.2.4, + any.wai-app-static ==3.1.9, + wai-app-static +crypton -print, + any.wai-extra ==3.1.15, + wai-extra -build-example, + any.wai-logger ==2.5.0, + any.warp ==3.4.2, + warp +allow-sendfilefd -network-bytestring -warp-debug +x509, + any.wide-word ==0.1.6.0, + any.witherable ==0.5, + any.word8 ==0.1.3, + any.zlib ==0.7.1.0, + zlib -bundled-c-zlib +non-blocking-ffi +pkg-config +index-state: hackage.haskell.org 2024-10-11T12:55:31Z diff --git a/exblo-server.cabal b/exblo-server.cabal index fa13cca..0c6ceac 100644 --- a/exblo-server.cabal +++ b/exblo-server.cabal @@ -1,6 +1,6 @@ cabal-version: 3.4 name: exblo-server -version: 0.1.0.0 +version: 0.2.0.0 -- synopsis: -- description: homepage: https://vergara.tech/exblo @@ -19,13 +19,17 @@ common warnings library import: warnings - exposed-modules: Server + exposed-modules: + Server + , Types -- other-modules: -- other-extensions: build-depends: base ^>=4.18.2.1 + , bytestring , servant-server , hexstring + , scientific , text , aeson , base16-bytestring diff --git a/src/Server.hs b/src/Server.hs index 1357ec7..0090ddd 100644 --- a/src/Server.hs +++ b/src/Server.hs @@ -12,45 +12,77 @@ module Server where import Control.Monad.IO.Class (liftIO) import Data.Aeson -import qualified Data.ByteString.Base16 as BS16 (decode) +import qualified Data.ByteString.Char8 as C +import qualified Data.ByteString.Lazy as LBS import Data.HexString +import Data.Scientific (scientific) import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Servant +import Types (ExbloInfo(..)) import ZcashHaskell.Types - ( RawZebraTx(..) + ( BlockResponse(..) + , RawZebraTx(..) , Transaction(..) , ZebraGetBlockChainInfo(..) + , ZebraGetInfo(..) , ZebraTxResponse(..) , fromRawOBundle , fromRawSBundle , fromRawTBundle ) -import ZcashHaskell.Utils (makeZebraCall, readZebraTransaction) - -instance FromHttpApiData HexString where - parseUrlPiece s = - case BS16.decode (TE.encodeUtf8 s) of - Right s -> Right $ HexString s - Left e -> Left $ T.pack e +import ZcashHaskell.Utils (getBlockTime, makeZebraCall, readZebraTransaction) type ExbloAPI = "getblock" :> Get '[ JSON] Int -- getblock :<|> "gettransaction" :> Capture "txid" HexString :> Get '[ JSON] Transaction -- gettransaction + :<|> "getinfo" :> Get '[ JSON] ExbloInfo -- getinfo + :<|> "getblockinfo" :> Capture "blkid" T.Text :> Get '[ JSON] BlockResponse api :: Proxy ExbloAPI api = Proxy exbloServer :: Server ExbloAPI -exbloServer = handleAPI :<|> handleTx +exbloServer = handleBlockheight :<|> handleTx :<|> handleInfo :<|> handleBlock where - handleAPI :: Handler Int - handleAPI = do + handleBlock :: T.Text -> Handler BlockResponse + handleBlock i = do + s <- + liftIO $ + makeZebraCall + "localhost" + 18232 + "getblock" + [Data.Aeson.String i, jsonNumber 1] + case s of + Left e -> throwError $ err400 {errBody = LBS.fromStrict $ C.pack e} + Right br -> do + s1 <- + liftIO $ + makeZebraCall + "localhost" + 18232 + "getblock" + [Data.Aeson.String i, jsonNumber 0] + case s1 of + Left e1 -> + throwError $ err400 {errBody = LBS.fromStrict $ C.pack e1} + Right blk -> do + let blocktime = getBlockTime blk + return $ + BlockResponse + (bl_hash br) + (bl_confirmations br) + (bl_height br) + (fromIntegral blocktime) + (bl_txs br) + handleBlockheight :: Handler Int + handleBlockheight = do s <- liftIO $ makeZebraCall "localhost" 18232 "getblockchaininfo" [] case s of - Left e -> fail e + Left e -> throwError $ err400 {errBody = LBS.fromStrict $ C.pack e} Right bci -> return $ zgb_blocks bci handleTx :: HexString -> Handler Transaction handleTx i = do @@ -62,10 +94,11 @@ exbloServer = handleAPI :<|> handleTx "getrawtransaction" [Data.Aeson.String $ toText i, Data.Aeson.Number 1] case s of - Left e -> fail e + Left e -> throwError $ err400 {errBody = LBS.fromStrict $ C.pack e} Right t -> case readZebraTransaction (ztr_hex t) of - Nothing -> fail "Unable to parse transaction" + Nothing -> + throwError $ err400 {errBody = "Unable to parse transaction"} Just tx -> return $ Transaction @@ -76,6 +109,21 @@ exbloServer = handleAPI :<|> handleTx (fromRawTBundle $ zt_tBundle tx) (fromRawSBundle $ zt_sBundle tx) (fromRawOBundle $ zt_oBundle tx) + handleInfo :: Handler ExbloInfo + handleInfo = do + s <- liftIO $ makeZebraCall "localhost" 18232 "getinfo" [] + case s of + Left e -> throwError $ err400 {errBody = LBS.fromStrict $ C.pack e} + Right bi -> do + s1 <- liftIO $ makeZebraCall "localhost" 18232 "getblockchaininfo" [] + case s1 of + Left e1 -> + throwError $ err400 {errBody = LBS.fromStrict $ C.pack e1} + Right bci -> + return $ ExbloInfo (zgb_net bci) (zgi_build bi) "0.1.0.0" exbloApp :: Application exbloApp = serve api exbloServer + +jsonNumber :: Int -> Value +jsonNumber i = Number $ scientific (fromIntegral i) 0 diff --git a/src/Types.hs b/src/Types.hs new file mode 100644 index 0000000..7b0d3fb --- /dev/null +++ b/src/Types.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module Types where + +import Data.Aeson +import Data.Aeson.TH (deriveJSON) +import qualified Data.Text as T +import ZcashHaskell.Types (ZcashNet) + +data ExbloInfo = ExbloInfo + { ex_net :: ZcashNet + , ex_zebra :: T.Text + , ex_version :: T.Text + } deriving (Eq, Show) + +$(deriveJSON defaultOptions {fieldLabelModifier = drop 3} ''ExbloInfo) diff --git a/zcash-haskell b/zcash-haskell index 0b2fae2..396f151 160000 --- a/zcash-haskell +++ b/zcash-haskell @@ -1 +1 @@ -Subproject commit 0b2fae2b5db6878b7669d639a5cb8c73b986906e +Subproject commit 396f15140a00fd9a00f06c89910f76a22354e8d8