merkle-patricia-db-0.1.0: src/Blockchain/Database/MerklePatricia/StateRoot.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
module Blockchain.Database.MerklePatricia.StateRoot (
StateRoot(..),
emptyTriePtr,
sha2StateRoot,
unboxStateRoot,
formatStateRoot
) where
import Control.Monad
import qualified Data.ByteString.Base16 as B16
import Data.ByteArray (convert)
import Crypto.Hash as Crypto
import Data.Binary
import qualified Data.ByteString as B
import Data.String
import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8)
import Blockchain.Data.RLP
import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
import GHC.Generics
-- | Internal nodes are indexed in the underlying database by their 256-bit SHA3 hash.
-- This types represents said hash.
--
-- The stateRoot is of this type,
-- (ie- the pointer to the full set of key/value pairs at a particular time in history), and
-- will be of interest if you need to refer to older or parallel version of the data.
newtype StateRoot = StateRoot B.ByteString deriving (Show, Eq, Read, Generic, IsString)
formatStateRoot :: StateRoot -> String
formatStateRoot (StateRoot sr) = T.unpack . decodeUtf8 . B16.encode $ sr
instance Pretty StateRoot where
pretty = text . formatStateRoot
instance Binary StateRoot where
put (StateRoot x) = sequence_ $ put <$> B.unpack x
get = StateRoot <$> B.pack <$> replicateM 32 get
instance RLPSerializable StateRoot where
rlpEncode (StateRoot x) = rlpEncode x
rlpDecode x = StateRoot $ rlpDecode x
-- | The stateRoot of the empty database.
emptyTriePtr::StateRoot
emptyTriePtr =
let root = rlpEncode (0::Integer)
rootHash = convert $ (Crypto.hash . rlpSerialize $ root :: Crypto.Digest Crypto.Keccak_256)
in StateRoot rootHash
sha2StateRoot::Digest Crypto.Keccak_256 -> StateRoot
sha2StateRoot = StateRoot . convert
unboxStateRoot :: StateRoot -> B.ByteString
unboxStateRoot (StateRoot b) = b