-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validators module #253
Merged
Merged
Validators module #253
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2b53a24
Validators module draft
UnitylChaos f1ad47c
hlint
UnitylChaos 3d8bade
StateT, Keeper method removal, protobufs
UnitylChaos 2be7dfd
cs instead of pack; weeder fixes
UnitylChaos c875afe
revert Maybe PubKey -> PubKey
UnitylChaos ea39d8c
error message on getQueuedUpdatesF
UnitylChaos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
module Tendermint.SDK.Modules.Validators | ||
( | ||
Validators | ||
, validatorsModule | ||
|
||
, module Tendermint.SDK.Modules.Validators.Keeper | ||
, module Tendermint.SDK.Modules.Validators.Types | ||
|
||
, endBlock | ||
) where | ||
|
||
|
||
import Polysemy (Members) | ||
import Tendermint.SDK.Application (Module (..), | ||
ModuleEffs) | ||
import Tendermint.SDK.BaseApp (EmptyTxServer (..)) | ||
import Tendermint.SDK.Modules.Validators.EndBlock | ||
import Tendermint.SDK.Modules.Validators.Keeper | ||
import Tendermint.SDK.Modules.Validators.Query | ||
import Tendermint.SDK.Modules.Validators.Types | ||
|
||
|
||
type Validators = Module ValidatorsName EmptyTxServer EmptyTxServer QueryApi ValidatorsEffs '[] | ||
|
||
validatorsModule :: | ||
Members (ModuleEffs Validators) r => | ||
Validators r | ||
validatorsModule = | ||
Module | ||
{ moduleTxDeliverer = EmptyTxServer, | ||
moduleTxChecker = EmptyTxServer, | ||
moduleQuerier = querier, | ||
moduleEval = eval | ||
} | ||
|
52 changes: 52 additions & 0 deletions
52
hs-abci-sdk/src/Tendermint/SDK/Modules/Validators/EndBlock.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
module Tendermint.SDK.Modules.Validators.EndBlock where | ||
|
||
import Control.Monad.State (MonadTrans (lift), | ||
execStateT, forM_, | ||
modify) | ||
import qualified Data.Map.Strict as Map | ||
import qualified Data.Set as Set | ||
import qualified Network.ABCI.Types.Messages.FieldTypes as ABCI | ||
import qualified Network.ABCI.Types.Messages.Request as Request | ||
import Polysemy (Members, Sem) | ||
import Tendermint.SDK.BaseApp (BlockEffs, | ||
EndBlockResult (..)) | ||
import qualified Tendermint.SDK.BaseApp.Store.List as L | ||
import qualified Tendermint.SDK.BaseApp.Store.Map as M | ||
import qualified Tendermint.SDK.BaseApp.Store.Var as V | ||
import Tendermint.SDK.Modules.Validators.Keeper | ||
import Tendermint.SDK.Modules.Validators.Store | ||
import Tendermint.SDK.Modules.Validators.Types | ||
|
||
|
||
endBlock | ||
:: Members BlockEffs r | ||
=> Members ValidatorsEffs r | ||
=> Request.EndBlock | ||
-> Sem r EndBlockResult | ||
endBlock _ = do | ||
updatesMap <- getQueuedUpdates | ||
curValKeySet <- getValidatorsKeys | ||
|
||
-- update the Validators map and key set | ||
newValKeySet <- flip execStateT curValKeySet $ | ||
forM_ (Map.toList updatesMap) $ \(key, newPower) -> | ||
if newPower == 0 then do | ||
-- delete from Validators map and key set | ||
lift $ M.delete key validatorsMap | ||
modify $ Set.delete key | ||
else do | ||
-- update power in Validators map and ensure key is in key set | ||
lift $ M.insert key newPower validatorsMap | ||
modify $ Set.insert key | ||
|
||
-- store new set of validator keys | ||
V.putVar (KeySet newValKeySet) validatorsKeySet | ||
|
||
-- reset the updatesList to empty | ||
L.deleteWhen (const True) updatesList | ||
|
||
-- return EndBlockResult with validator updates for Tendermint | ||
pure $ EndBlockResult (map convertToValUp (Map.assocs updatesMap)) Nothing | ||
where | ||
convertToValUp (PubKey_ key, power) = | ||
ABCI.ValidatorUpdate (Just key) (ABCI.WrappedVal (fromIntegral power)) |
74 changes: 74 additions & 0 deletions
74
hs-abci-sdk/src/Tendermint/SDK/Modules/Validators/Keeper.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
{-# LANGUAGE TemplateHaskell #-} | ||
|
||
module Tendermint.SDK.Modules.Validators.Keeper where | ||
|
||
import qualified Data.Map.Strict as Map | ||
import Data.Maybe (fromMaybe) | ||
import qualified Data.Set as Set | ||
import Data.Word (Word64) | ||
import Network.ABCI.Types.Messages.FieldTypes | ||
import Polysemy (Members, Sem, | ||
interpret, makeSem) | ||
import Polysemy.Error (Error) | ||
import Tendermint.SDK.BaseApp (AppError, ReadStore, | ||
WriteStore) | ||
import qualified Tendermint.SDK.BaseApp.Store.List as L | ||
import qualified Tendermint.SDK.BaseApp.Store.Map as M | ||
import qualified Tendermint.SDK.BaseApp.Store.Var as V | ||
import Tendermint.SDK.Modules.Validators.Store | ||
import Tendermint.SDK.Modules.Validators.Types | ||
|
||
|
||
data ValidatorsKeeper m a where | ||
GetValidatorsKeys :: ValidatorsKeeper m (Set.Set PubKey_) | ||
GetPowerOf :: PubKey_ -> ValidatorsKeeper m Word64 | ||
GetQueuedUpdates :: ValidatorsKeeper m (Map.Map PubKey_ Word64) | ||
QueueUpdate :: PubKey_ -> Word64 -> ValidatorsKeeper m () | ||
|
||
makeSem ''ValidatorsKeeper | ||
|
||
type ValidatorsEffs = '[ValidatorsKeeper] | ||
|
||
eval | ||
:: Members [ReadStore, WriteStore, Error AppError] r | ||
=> Sem (ValidatorsKeeper : r) a | ||
-> Sem r a | ||
eval = interpret (\case | ||
GetValidatorsKeys -> getValidatorsKeysF | ||
GetPowerOf key -> getPowerOfF key | ||
GetQueuedUpdates -> getQueuedUpdatesF | ||
QueueUpdate key power -> queueUpdateF key power | ||
) | ||
|
||
getValidatorsKeysF | ||
:: Members [ReadStore, Error AppError] r | ||
=> Sem r (Set.Set PubKey_) | ||
getValidatorsKeysF = | ||
fmap (maybe Set.empty (\(KeySet x) -> x)) $ V.takeVar validatorsKeySet | ||
|
||
getPowerOfF | ||
:: Members [ReadStore, Error AppError] r | ||
=> PubKey_ | ||
-> Sem r Word64 | ||
getPowerOfF key = | ||
fmap (fromMaybe 0) $ M.lookup key validatorsMap | ||
|
||
getQueuedUpdatesF | ||
:: Members [ReadStore, Error AppError] r | ||
=> Sem r (Map.Map PubKey_ Word64) | ||
getQueuedUpdatesF = L.foldl (\m (ValidatorUpdate_ ValidatorUpdate{..}) -> | ||
Map.alter (Just . fromMaybe (toWord validatorUpdatePower)) (toPK_ validatorUpdatePubKey) m) Map.empty updatesList | ||
where | ||
toWord (WrappedVal x) = fromIntegral x | ||
toPK_ = PubKey_ . fromMaybe (error "Bad ValidatorUpdate with Nothing PubKey found in queued updates") | ||
|
||
queueUpdateF | ||
:: Members [ReadStore, WriteStore, Error AppError] r | ||
=> PubKey_ | ||
-> Word64 | ||
-> Sem r () | ||
queueUpdateF (PubKey_ key) power = | ||
L.append (ValidatorUpdate_(ValidatorUpdate (Just key) (wrapInt power))) updatesList | ||
where | ||
wrapInt p = WrappedVal (fromIntegral p) | ||
|
57 changes: 57 additions & 0 deletions
57
hs-abci-sdk/src/Tendermint/SDK/Modules/Validators/Query.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
module Tendermint.SDK.Modules.Validators.Query | ||
( | ||
querier | ||
, QueryApi | ||
)where | ||
|
||
import qualified Data.Map.Strict as Map | ||
import qualified Data.Set as Set | ||
import Data.Word (Word64) | ||
import Polysemy (Members, Sem) | ||
import Servant.API | ||
import Tendermint.SDK.BaseApp | ||
import qualified Tendermint.SDK.BaseApp.Store.Map as M | ||
import qualified Tendermint.SDK.BaseApp.Store.Var as V | ||
import qualified Tendermint.SDK.Modules.Validators.Keeper as Keeper | ||
import Tendermint.SDK.Modules.Validators.Store | ||
import Tendermint.SDK.Modules.Validators.Types | ||
|
||
type QueryApi = GetPowerOf :<|> GetValidatorsKeys :<|> GetValidators | ||
|
||
querier | ||
:: Members QueryEffs r | ||
=> Members Keeper.ValidatorsEffs r | ||
=> RouteQ QueryApi r | ||
querier = | ||
getPowerOfQuery :<|> getValidatorsKeys :<|> getValidators | ||
|
||
type GetPowerOf = "powerOf" :> StoreLeaf (M.Map PubKey_ Word64) | ||
getPowerOfQuery | ||
:: Members QueryEffs r | ||
=> RouteQ GetPowerOf r | ||
getPowerOfQuery = storeQueryHandler validatorsMap | ||
|
||
type GetValidatorsKeys = "validatorsKeys" :> StoreLeaf (V.Var KeySet) | ||
getValidatorsKeys | ||
:: Members QueryEffs r | ||
=> RouteQ GetValidatorsKeys r | ||
getValidatorsKeys = storeQueryHandler validatorsKeySet | ||
|
||
type GetValidators = "validators" :> Leaf (Map.Map PubKey_ Word64) | ||
getValidators | ||
:: Members Keeper.ValidatorsEffs r | ||
=> Sem r (QueryResult (Map.Map PubKey_ Word64)) | ||
getValidators = do | ||
keyList <- fmap Set.toList Keeper.getValidatorsKeys | ||
vs <- fmap Map.fromList $ mapM (\k -> fmap (\p -> (k, p)) (Keeper.getPowerOf k)) keyList | ||
pure $ QueryResult | ||
{ queryResultData = vs | ||
, queryResultIndex = 0 | ||
, queryResultKey = "" | ||
, queryResultProof = Nothing | ||
, queryResultHeight = 0 | ||
} | ||
|
||
|
||
|
||
|
28 changes: 28 additions & 0 deletions
28
hs-abci-sdk/src/Tendermint/SDK/Modules/Validators/Store.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{-# LANGUAGE TemplateHaskell #-} | ||
|
||
module Tendermint.SDK.Modules.Validators.Store | ||
( | ||
updatesList | ||
, validatorsMap | ||
, validatorsKeySet | ||
) where | ||
|
||
import Data.Word (Word64) | ||
import Tendermint.SDK.BaseApp (KeyRoot (..), Store, | ||
makeStore) | ||
import qualified Tendermint.SDK.BaseApp.Store.List as L | ||
import qualified Tendermint.SDK.BaseApp.Store.Map as M | ||
import Tendermint.SDK.BaseApp.Store.TH (makeSubStore) | ||
import qualified Tendermint.SDK.BaseApp.Store.Var as V | ||
import Tendermint.SDK.Modules.Validators.Types | ||
|
||
|
||
store :: Store ValidatorsNameSpace | ||
store = makeStore $ KeyRoot "validators" | ||
|
||
$(makeSubStore 'store "updatesList" [t|L.List ValidatorUpdate_|] updatesListKey) | ||
|
||
$(makeSubStore 'store "validatorsMap" [t|M.Map PubKey_ Word64|] validatorsMapKey) | ||
|
||
$(makeSubStore 'store "validatorsKeySet" [t|V.Var KeySet|] validatorsKeySetKey) | ||
|
59 changes: 59 additions & 0 deletions
59
hs-abci-sdk/src/Tendermint/SDK/Modules/Validators/Types.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module Tendermint.SDK.Modules.Validators.Types where | ||
|
||
import Control.Lens (Wrapped (_Wrapped'), | ||
iso, (^.), _Unwrapped') | ||
import qualified Data.Aeson as A | ||
import Data.Bifunctor (Bifunctor (bimap, second)) | ||
import Data.ByteString (ByteString) | ||
import Data.ByteString.Lazy (toStrict) | ||
import Data.Either (fromRight) | ||
import Data.ProtoLens (decodeMessage, | ||
encodeMessage) | ||
import Data.Set (Set) | ||
import Data.String.Conversions (cs) | ||
import GHC.Generics (Generic) | ||
import Network.ABCI.Types.Messages.FieldTypes (PubKey (PubKey), | ||
ValidatorUpdate) | ||
import Tendermint.SDK.BaseApp (RawKey (..)) | ||
import Tendermint.SDK.Codec (HasCodec (..)) | ||
|
||
|
||
data ValidatorsNameSpace | ||
|
||
type ValidatorsName = "validators" | ||
|
||
|
||
updatesListKey :: ByteString | ||
updatesListKey = "updatesList" | ||
|
||
validatorsMapKey :: ByteString | ||
validatorsMapKey = "validatorsMap" | ||
|
||
validatorsKeySetKey :: ByteString | ||
validatorsKeySetKey = "validatorsKeySet" | ||
|
||
|
||
newtype ValidatorUpdate_ = ValidatorUpdate_ ValidatorUpdate deriving (Eq, Generic) | ||
|
||
instance HasCodec ValidatorUpdate_ where | ||
encode (ValidatorUpdate_ vu) = encodeMessage $ (vu ^. _Wrapped') | ||
decode bs = bimap cs (ValidatorUpdate_ . (^. _Unwrapped')) $ decodeMessage bs | ||
|
||
newtype PubKey_ = PubKey_ PubKey deriving (Eq, Ord, Generic) | ||
|
||
instance RawKey PubKey_ where | ||
rawKey = iso t f | ||
where | ||
t (PubKey_ p) = encodeMessage $ (p ^. _Wrapped') | ||
f = PubKey_ . fromRight (PubKey "" "") . second (^. _Unwrapped') . decodeMessage | ||
|
||
|
||
instance A.ToJSON PubKey_ | ||
instance A.FromJSON PubKey_ | ||
|
||
newtype KeySet = KeySet (Set PubKey_) deriving Generic | ||
instance A.ToJSON KeySet | ||
instance A.FromJSON KeySet | ||
instance HasCodec KeySet where | ||
encode = toStrict . A.encode | ||
decode s = maybe (Left "failure to decode KeySet") Right (A.decodeStrict s) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine, but as a note I'm sort of remembering that there is actually no instance where the
from
method of the iso is being used, we're almost always using it as a value of type:: Lens' a ByteString
. This is why thePubKey "" ""
seems awkward, I will get around to fixing this soon.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #255
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re
PubKey "" ""
:I figured this would be okay, since the only time it would be deserializing would be if it was reading the bytes from the db. And they must have been serialized from the pubkey to get put in the DB, so it should never fail. Definitely is awkward thought...