{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Test.Cardano.Ledger.Dijkstra.Imp.PoolSpec (spec) where
import Cardano.Ledger.BaseTypes (StrictMaybe (..))
import Cardano.Ledger.Coin (Coin (..))
import Cardano.Ledger.Credential (Credential (..))
import Cardano.Ledger.Dijkstra.Core
import Cardano.Ledger.Dijkstra.PParams (ppMaxPledgeLeverageL)
import Cardano.Ledger.Shelley.LedgerState (nesEsL)
import Cardano.Ledger.State (EraCertState, StakePoolParams (..), casReservesL, chainAccountStateL)
import Data.Coerce (coerce)
import Data.Foldable (fold)
import qualified Data.Set as Set
import Lens.Micro ((&), (.~))
import Test.Cardano.Ledger.Core.Rational ((%!))
import Test.Cardano.Ledger.Dijkstra.ImpTest
import Test.Cardano.Ledger.Imp.Common
reserves :: Coin
reserves :: Coin
reserves = Integer -> Coin
Coin Integer
20_000_000_000_000_000
ownerStake :: Coin
ownerStake :: Coin
ownerStake = Integer -> Coin
Coin Integer
10_000_000_000_000
delegatorStake :: Coin
delegatorStake :: Coin
delegatorStake = Integer -> Coin
Coin Integer
90_000_000_000_000
registerPoolWithPledge ::
DijkstraEraImp era =>
Coin ->
ImpTestM era (KeyHash StakePool, [Credential Staking])
registerPoolWithPledge :: forall era.
DijkstraEraImp era =>
Coin -> ImpTestM era (KeyHash StakePool, [Credential Staking])
registerPoolWithPledge Coin
pledge = do
poolId <- ImpM (LedgerSpec era) (KeyHash StakePool)
forall (r :: KeyRole) s g (m :: * -> *).
(HasKeyPairs s, MonadState s m, HasStatefulGen g m) =>
m (KeyHash r)
freshKeyHash
ownerKeyHash <- freshKeyHash
delegatorKeyHash <- freshKeyHash
let owner = KeyHash Staking -> Credential Staking
forall (kr :: KeyRole). KeyHash kr -> Credential kr
KeyHashObj KeyHash Staking
ownerKeyHash
delegator = KeyHash Staking -> Credential Staking
forall (kr :: KeyRole). KeyHash kr -> Credential kr
KeyHashObj KeyHash Staking
delegatorKeyHash
ownerPayment <- freshKeyHash @Payment
delegatorPayment <- freshKeyHash @Payment
sendCoinTo_ (mkAddr ownerPayment owner) ownerStake
sendCoinTo_ (mkAddr delegatorPayment delegator) delegatorStake
ownerAccountAddress <- registerStakeCredential owner
_ <- registerStakeCredential delegator
minPoolCost <- getsPParams ppMinPoolCostL
registerPoolWithParams
( \StakePoolParams
poolParams ->
StakePoolParams
poolParams
{ sppPledge = pledge
, sppOwners = Set.singleton ownerKeyHash
, sppCost = minPoolCost
, sppMargin = 0 %! 1
}
)
poolId
ownerAccountAddress
delegateStake owner poolId
delegateStake delegator poolId
pure (poolId, [owner, delegator])
poolRewards :: (HasCallStack, EraCertState era) => [Credential Staking] -> ImpTestM era Coin
poolRewards :: forall era.
(HasCallStack, EraCertState era) =>
[Credential Staking] -> ImpTestM era Coin
poolRewards = ([Coin] -> Coin)
-> ImpM (LedgerSpec era) [Coin] -> ImpM (LedgerSpec era) Coin
forall a b.
(a -> b) -> ImpM (LedgerSpec era) a -> ImpM (LedgerSpec era) b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Coin] -> Coin
forall m. Monoid m => [m] -> m
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold (ImpM (LedgerSpec era) [Coin] -> ImpM (LedgerSpec era) Coin)
-> ([Credential Staking] -> ImpM (LedgerSpec era) [Coin])
-> [Credential Staking]
-> ImpM (LedgerSpec era) Coin
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Credential Staking -> ImpM (LedgerSpec era) Coin)
-> [Credential Staking] -> ImpM (LedgerSpec era) [Coin]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse Credential Staking -> ImpM (LedgerSpec era) Coin
forall era.
(HasCallStack, EraCertState era) =>
Credential Staking -> ImpTestM era Coin
getBalance
rewardsOfWellAndOverPledgedPools ::
DijkstraEraImp era =>
ImpTestM era (Coin, Coin)
rewardsOfWellAndOverPledgedPools :: forall era. DijkstraEraImp era => ImpTestM era (Coin, Coin)
rewardsOfWellAndOverPledgedPools = do
(NewEpochState era -> NewEpochState era) -> ImpTestM era ()
forall era.
(NewEpochState era -> NewEpochState era) -> ImpTestM era ()
modifyNES ((NewEpochState era -> NewEpochState era) -> ImpTestM era ())
-> (NewEpochState era -> NewEpochState era) -> ImpTestM era ()
forall a b. (a -> b) -> a -> b
$ (EpochState era -> Identity (EpochState era))
-> NewEpochState era -> Identity (NewEpochState era)
forall era (f :: * -> *).
Functor f =>
(EpochState era -> f (EpochState era))
-> NewEpochState era -> f (NewEpochState era)
nesEsL ((EpochState era -> Identity (EpochState era))
-> NewEpochState era -> Identity (NewEpochState era))
-> ((Coin -> Identity Coin)
-> EpochState era -> Identity (EpochState era))
-> (Coin -> Identity Coin)
-> NewEpochState era
-> Identity (NewEpochState era)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ChainAccountState -> Identity ChainAccountState)
-> EpochState era -> Identity (EpochState era)
forall era. Lens' (EpochState era) ChainAccountState
forall (t :: * -> *) era.
CanSetChainAccountState t =>
Lens' (t era) ChainAccountState
chainAccountStateL ((ChainAccountState -> Identity ChainAccountState)
-> EpochState era -> Identity (EpochState era))
-> ((Coin -> Identity Coin)
-> ChainAccountState -> Identity ChainAccountState)
-> (Coin -> Identity Coin)
-> EpochState era
-> Identity (EpochState era)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Coin -> Identity Coin)
-> ChainAccountState -> Identity ChainAccountState
Lens' ChainAccountState Coin
casReservesL ((Coin -> Identity Coin)
-> NewEpochState era -> Identity (NewEpochState era))
-> Coin -> NewEpochState era -> NewEpochState era
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Coin
reserves
wellPledged <- Coin -> ImpTestM era (KeyHash StakePool, [Credential Staking])
forall era.
DijkstraEraImp era =>
Coin -> ImpTestM era (KeyHash StakePool, [Credential Staking])
registerPoolWithPledge Coin
ownerStake
overLeveraged <- registerPoolWithPledge $ Coin (unCoin ownerStake `div` 1_000)
passNEpochs 2
replicateM_ 3 $
forM_ [fst wellPledged, fst overLeveraged] $ \KeyHash StakePool
poolId ->
KeyHash BlockIssuer -> ImpTestM era () -> ImpTestM era ()
forall era a.
(HasCallStack, ShelleyEraImp era) =>
KeyHash BlockIssuer -> ImpTestM era a -> ImpTestM era ()
withIssuerAndTxsInBlock_ (KeyHash StakePool -> KeyHash BlockIssuer
forall a b. Coercible a b => a -> b
coerce KeyHash StakePool
poolId) (ImpTestM era () -> ImpTestM era ())
-> ImpTestM era () -> ImpTestM era ()
forall a b. (a -> b) -> a -> b
$ do
addr <- ImpM (LedgerSpec era) Addr
forall s (m :: * -> *) g.
(HasKeyPairs s, MonadState s m, HasStatefulGen g m, MonadGen m) =>
m Addr
freshKeyAddr_
sendCoinTo_ addr $ Coin 1_000_000_000
passNEpochs 3
(,) <$> poolRewards (snd wellPledged) <*> poolRewards (snd overLeveraged)
spec :: forall era. DijkstraEraImp era => SpecWith (ImpInit (LedgerSpec era))
spec :: forall era.
DijkstraEraImp era =>
SpecWith (ImpInit (LedgerSpec era))
spec = String
-> SpecWith (ImpInit (LedgerSpec era))
-> SpecWith (ImpInit (LedgerSpec era))
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"POOL" (SpecWith (ImpInit (LedgerSpec era))
-> SpecWith (ImpInit (LedgerSpec era)))
-> SpecWith (ImpInit (LedgerSpec era))
-> SpecWith (ImpInit (LedgerSpec era))
forall a b. (a -> b) -> a -> b
$ do
String
-> SpecWith (ImpInit (LedgerSpec era))
-> SpecWith (ImpInit (LedgerSpec era))
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"maxPledgeLeverage" (SpecWith (ImpInit (LedgerSpec era))
-> SpecWith (ImpInit (LedgerSpec era)))
-> SpecWith (ImpInit (LedgerSpec era))
-> SpecWith (ImpInit (LedgerSpec era))
forall a b. (a -> b) -> a -> b
$ do
let withoutPledgeInfluence :: ImpM (LedgerSpec era) ()
withoutPledgeInfluence = (PParams era -> PParams era) -> ImpM (LedgerSpec era) ()
forall era.
ShelleyEraImp era =>
(PParams era -> PParams era) -> ImpTestM era ()
modifyPParams ((PParams era -> PParams era) -> ImpM (LedgerSpec era) ())
-> (PParams era -> PParams era) -> ImpM (LedgerSpec era) ()
forall a b. (a -> b) -> a -> b
$ \PParams era
pp -> PParams era
pp PParams era -> (PParams era -> PParams era) -> PParams era
forall a b. a -> (a -> b) -> b
& (NonNegativeInterval -> Identity NonNegativeInterval)
-> PParams era -> Identity (PParams era)
forall era.
EraPParams era =>
Lens' (PParams era) NonNegativeInterval
Lens' (PParams era) NonNegativeInterval
ppA0L ((NonNegativeInterval -> Identity NonNegativeInterval)
-> PParams era -> Identity (PParams era))
-> NonNegativeInterval -> PParams era -> PParams era
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Integer
0 Integer -> Integer -> NonNegativeInterval
forall r. (IsRatio r, HasCallStack) => Integer -> Integer -> r
%! Integer
1
String
-> ImpM (LedgerSpec era) ()
-> SpecWith (Arg (ImpM (LedgerSpec era) ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"is not enforced when it is not set" (ImpM (LedgerSpec era) ()
-> SpecWith (Arg (ImpM (LedgerSpec era) ())))
-> ImpM (LedgerSpec era) ()
-> SpecWith (Arg (ImpM (LedgerSpec era) ()))
forall a b. (a -> b) -> a -> b
$ do
ImpM (LedgerSpec era) ()
withoutPledgeInfluence
(wellPledgedRewards, overLeveragedRewards) <- ImpTestM era (Coin, Coin)
forall era. DijkstraEraImp era => ImpTestM era (Coin, Coin)
rewardsOfWellAndOverPledgedPools
wellPledgedRewards `shouldSatisfy` (> Coin 0)
overLeveragedRewards `shouldBe` wellPledgedRewards
String
-> ImpM (LedgerSpec era) ()
-> SpecWith (Arg (ImpM (LedgerSpec era) ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"lowers the rewards of a pool that is leveraged beyond it" (ImpM (LedgerSpec era) ()
-> SpecWith (Arg (ImpM (LedgerSpec era) ())))
-> ImpM (LedgerSpec era) ()
-> SpecWith (Arg (ImpM (LedgerSpec era) ()))
forall a b. (a -> b) -> a -> b
$ do
ImpM (LedgerSpec era) ()
withoutPledgeInfluence
(PParams era -> PParams era) -> ImpM (LedgerSpec era) ()
forall era.
ShelleyEraImp era =>
(PParams era -> PParams era) -> ImpTestM era ()
modifyPParams ((PParams era -> PParams era) -> ImpM (LedgerSpec era) ())
-> (PParams era -> PParams era) -> ImpM (LedgerSpec era) ()
forall a b. (a -> b) -> a -> b
$ \PParams era
pp ->
PParams era
pp PParams era -> (PParams era -> PParams era) -> PParams era
forall a b. a -> (a -> b) -> b
& (MaxPledgeLeverage -> Identity MaxPledgeLeverage)
-> PParams era -> Identity (PParams era)
forall era.
DijkstraEraPParams era =>
Lens' (PParams era) MaxPledgeLeverage
Lens' (PParams era) MaxPledgeLeverage
ppMaxPledgeLeverageL ((MaxPledgeLeverage -> Identity MaxPledgeLeverage)
-> PParams era -> Identity (PParams era))
-> MaxPledgeLeverage -> PParams era -> PParams era
forall s t a b. ASetter s t a b -> b -> s -> t
.~ StrictMaybe NonNegativeInterval -> MaxPledgeLeverage
MaxPledgeLeverage (NonNegativeInterval -> StrictMaybe NonNegativeInterval
forall a. a -> StrictMaybe a
SJust (Integer
10 Integer -> Integer -> NonNegativeInterval
forall r. (IsRatio r, HasCallStack) => Integer -> Integer -> r
%! Integer
1))
(wellPledgedRewards, overLeveragedRewards) <- ImpTestM era (Coin, Coin)
forall era. DijkstraEraImp era => ImpTestM era (Coin, Coin)
rewardsOfWellAndOverPledgedPools
wellPledgedRewards `shouldSatisfy` (> Coin 0)
overLeveragedRewards `shouldSatisfy` (> Coin 0)
Coin (100 * unCoin overLeveragedRewards) `shouldSatisfy` (< wellPledgedRewards)