blockchain-0.0.3: lib/Data/Blockchain/Types/Hex.hs
module Data.Blockchain.Types.Hex
( Hex256(..)
, hex256
, hex256LeadingZeros
) where
import Control.Monad (unless)
import qualified Data.Aeson as Aeson
import qualified Data.Maybe as Maybe
import Data.Monoid ((<>))
import qualified Data.Text as Text
import qualified Data.Word as Word
import qualified Numeric
import qualified Numeric.Natural as Natural
-- Types -----------------------------------------------------------------------------------------------------
newtype Hex256 = Hex256 { unHex256 :: Natural.Natural }
deriving (Enum, Eq, Integral, Num, Real, Ord)
instance Show Hex256 where
show = zeroPadded 64 . showHex . unHex256
instance Bounded Hex256 where
minBound = 0
maxBound = Maybe.fromMaybe (error "Unexpected parse failure") $ readHexMaybe $ replicate 64 'f'
instance Aeson.ToJSON Hex256 where
toJSON = Aeson.String . Text.pack . show
instance Aeson.FromJSON Hex256 where
parseJSON = Aeson.withText "Hex256" parseHex256
where
parseHex256 = maybe (fail "Invalid hex 256 string") return . hex256 . Text.unpack
-- Construction helpers --------------------------------------------------------------------------------------
-- | Create a Hex256 value with the specificed amount of leading zeros.
-- Useful for creating a 'Data.Blockchain.Types.BlockchainConfig.difficulty1Target' when creating a blockchain.
--
-- >>> hex256LeadingZeros 4
-- 0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
--
hex256LeadingZeros :: Word.Word -> Hex256
hex256LeadingZeros n = maxBound `div` Hex256 (16 ^ n)
hex256 :: String -> Maybe Hex256
hex256 str = do
unless (length str == 64) Nothing
x <- readHexMaybe str
return (Hex256 x)
readHexMaybe :: (Num a, Eq a) => String -> Maybe a
readHexMaybe str = case Numeric.readHex str of
[(x, "")] -> Just x
_ -> Nothing
-- Utils -----------------------------------------------------------------------------------------------------
showHex :: (Show a, Integral a) => a -> String
showHex x = Numeric.showHex x mempty
zeroPadded :: Int -> String -> String
zeroPadded x str = replicate (x - length str) '0' <> str