module Bitcoin.Internal.Util ( module Bitcoin.Internal.Util , module X , cs , fmapL , (<>) , module Ctrl ) where import Bitcoin.Internal.Types as X import Data.Serialize as Bin import Data.Serialize.Get as BinGet import qualified Data.ByteString as B import qualified Data.Aeson.Types as JSON import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Char8 as C import qualified Data.Text as T import Data.Text.Encoding (decodeUtf8, encodeUtf8) import Data.Typeable (Typeable, typeOf) import qualified Network.Haskoin.Crypto as HC import Data.String.Conversions (cs) --import Data.Either (lefts) import Data.EitherR (fmapL) import Data.Monoid ((<>)) import Control.Monad as Ctrl (forM, mapM, (>=>), (<=<)) toInt :: (Integral a, Num b) => a -> b toInt = fromIntegral getIndexSafe :: [a] -> Int -> Maybe a getIndexSafe l i = if i < 0 || i+1 > length l then Nothing else Just $ l !! i toHexString :: B.ByteString -> String toHexString = C.unpack . B16.encode toHexBS :: B.ByteString -> B.ByteString toHexBS = B16.encode fromHexBS :: B.ByteString -> B.ByteString fromHexBS = fst . B16.decode fromHexString :: String -> B.ByteString fromHexString hexStr = case (B16.decode . C.pack) hexStr of (bs,e) -> if B.length e /= 0 then B.empty else bs serialize :: Bin.Serialize a => a -> B.ByteString serialize = Bin.encode deserEither :: forall a. (Typeable a, Bin.Serialize a) => B.ByteString -> Either String a deserEither bs = do let eitherRes' = BinGet.runGetPartial (Bin.get :: BinGet.Get a) bs handleResult eitherRes' where handleResult eitherRes = case eitherRes of BinGet.Done val _ -> Right val BinGet.Partial feedFunc -> handleResult $ feedFunc B.empty BinGet.Fail e leftoverBS -> Left $ "Type: " ++ show (typeOf (undefined :: a)) ++ ". Error: " ++ e ++ ". Data consumed (" ++ show offset ++ " bytes): " ++ toHexString (B.take offset bs) ++ ". Unconsumed data: (" ++ show ( B.length bs - fromIntegral offset ) ++ " bytes): " ++ toHexString leftoverBS where offset = B.length bs - B.length leftoverBS deserHex :: (Typeable a, Bin.Serialize a) => T.Text -> JSON.Parser a deserHex = either (fail . ("failed to decode hex: " ++)) return . deserEither . fromHexBS . encodeUtf8 serHex :: Bin.Serialize a => a -> T.Text serHex = decodeUtf8 . toHexBS . Bin.encode -- dummyPubkey :: HC.PubKeyC -- dummyPubkey = mkDummyPubkey "0323dcd0a7481cb90e3583923701b14d0b6757ebd76bf5b49e696c61f193d7a489" mkDummyPubkey :: B.ByteString -> HC.PubKeyC mkDummyPubkey hexStr = either (error "mkDummyPubkey: Invalid dummy pubkey data") id (Bin.decode pkBS) where pkBS = fst $ B16.decode hexStr mkDummySig :: B.ByteString -> HC.Signature mkDummySig hexStr = fromMaybe (error "dummySig: Invalid dummy sig data") (HC.decodeDerSig sigBS) where sigBS = fst $ B16.decode hexStr dummySig :: HC.Signature dummySig = mkDummySig "304402204202cdb61cb702aa62de312a8e5eada817d90c4e26c8b696780b14d1576f204f02203c134d0acb057d917508ca9baab241a4f66ebea32f7acceeaf621a334927e17701"