Skip to content

Commit e9600ef

Browse files
authored
Merge pull request IntersectMBO#5639 from IntersectMBO/mgalazyn/test/treasury-growth
Add a treasury growth test
2 parents 1bc4e0c + c18580c commit e9600ef

File tree

5 files changed

+125
-19
lines changed

5 files changed

+125
-19
lines changed

cardano-testnet/cardano-testnet.cabal

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ library
3838
, cardano-cli ^>= 8.20.3.0
3939
, cardano-crypto-class
4040
, cardano-crypto-wrapper
41+
, cardano-git-rev
4142
, cardano-ledger-alonzo
43+
, cardano-ledger-binary
44+
, cardano-ledger-byron
45+
, cardano-ledger-conway
4246
, cardano-ledger-conway
4347
, cardano-ledger-core
4448
, cardano-ledger-core:testlib
45-
, cardano-git-rev
46-
, cardano-ledger-core
47-
, cardano-ledger-binary
48-
, cardano-ledger-byron
4949
, cardano-ledger-shelley
5050
, cardano-node
5151
, cardano-ping ^>= 0.2.0.10
@@ -183,6 +183,7 @@ test-suite cardano-testnet-test
183183
Cardano.Testnet.Test.LedgerEvents.Gov.InfoAction
184184
Cardano.Testnet.Test.LedgerEvents.Gov.ProposeNewConstitutionSPO
185185
Cardano.Testnet.Test.LedgerEvents.SanityCheck
186+
Cardano.Testnet.Test.LedgerEvents.TreasuryGrowth
186187

187188
Cardano.Testnet.Test.Node.Shutdown
188189
Cardano.Testnet.Test.SubmitApi.Babbage.Transaction

cardano-testnet/src/Testnet/Components/Configuration.hs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import Data.Bifunctor
3434
import qualified Data.ByteString.Lazy as LBS
3535
import qualified Data.List as List
3636
import Data.String
37-
import Data.Word (Word32)
3837
import GHC.Stack (HasCallStack)
3938
import qualified GHC.Stack as GHC
4039
import Lens.Micro
@@ -98,7 +97,7 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) era shelleyGenesis (TmpAbsolute
9897
genesisShelleyDirAbs = takeDirectory genesisShelleyFpAbs
9998
genesisShelleyDir <- H.createDirectoryIfMissing genesisShelleyDirAbs
10099
let testnetMagic = sgNetworkMagic shelleyGenesis
101-
numStakeDelegators = 3
100+
numStakeDelegators = 3 :: Int
102101
startTime = sgSystemStart shelleyGenesis
103102

104103
-- TODO: We need to read the genesis files into Haskell and modify them
@@ -115,6 +114,8 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) era shelleyGenesis (TmpAbsolute
115114
-- 50 second epochs
116115
-- Epoch length should be "10 * k / f" where "k = securityParam, f = activeSlotsCoeff"
117116
H.rewriteJsonFile @Value genesisShelleyFpAbs $ \o -> o
117+
-- TODO: remove rho and tau adjustment after https://github.com/IntersectMBO/cardano-api/pull/425 gets
118+
-- integrated with newer cardano-api into node
118119
& L.key "protocolParams" . L.key "rho" . L._Number .~ 0.1
119120
& L.key "protocolParams" . L.key "tau" . L._Number .~ 0.1
120121
& L.key "securityParam" . L._Integer .~ 5
@@ -130,11 +131,11 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) era shelleyGenesis (TmpAbsolute
130131
execCli_
131132
[ convertToEraString era, "genesis", "create-testnet-data"
132133
, "--spec-shelley", genesisShelleyFpAbs
133-
, "--testnet-magic", show @Word32 testnetMagic
134-
, "--pools", show @Int numPoolNodes
134+
, "--testnet-magic", show testnetMagic
135+
, "--pools", show numPoolNodes
135136
, "--total-supply", show @Int 2_000_000_000_000
136137
, "--delegated-supply", show @Int 1_000_000_000_000
137-
, "--stake-delegators", show @Int numStakeDelegators
138+
, "--stake-delegators", show numStakeDelegators
138139
, "--utxo-keys", show numSeededUTxOKeys
139140
, "--drep-keys", "3"
140141
, "--start-time", DTC.formatIso8601 startTime
@@ -152,7 +153,6 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) era shelleyGenesis (TmpAbsolute
152153
forM_ files $ \file -> do
153154
H.note file
154155

155-
156156
-- TODO: This conway and alonzo genesis creation should be ultimately moved to create-testnet-data
157157
alonzoConwayTestGenesisJsonTargetFile <- H.noteShow (genesisShelleyDir </> "genesis.alonzo.json")
158158
gen <- H.evalEither $ first prettyError defaultAlonzoGenesis
@@ -161,10 +161,16 @@ createSPOGenesisAndFiles (NumPools numPoolNodes) era shelleyGenesis (TmpAbsolute
161161
conwayConwayTestGenesisJsonTargetFile <- H.noteShow (genesisShelleyDir </> "genesis.conway.json")
162162
H.evalIO $ LBS.writeFile conwayConwayTestGenesisJsonTargetFile $ Aeson.encode defaultConwayGenesis
163163

164-
H.renameFile (tempAbsPath' </> "byron-gen-command/genesis.json") (genesisByronDir </> "genesis.json")
165-
-- TODO: create-testnet-data outputs the new shelley genesis do genesis.json
164+
H.renameFile (tempAbsPath' </> "byron-gen-command" </> "genesis.json") (genesisByronDir </> "genesis.json")
165+
-- TODO: create-testnet-data outputs the new shelley genesis to genesis.json
166166
H.renameFile (tempAbsPath' </> "genesis.json") (genesisShelleyDir </> "genesis.shelley.json")
167167

168+
-- TODO: move this to create-testnet-data
169+
-- For some reason when setting "--total-supply 10E16" in create-testnet-data, we're getting negative
170+
-- treasury
171+
H.rewriteJsonFile @Value (genesisShelleyDir </> "genesis.shelley.json") $ \o -> o
172+
& L.key "maxLovelaceSupply" . L._Integer .~ 10_000_000_000_000_000
173+
168174
return genesisShelleyDir
169175

170176
ifaceAddress :: String

cardano-testnet/test/cardano-testnet-test/Cardano/Testnet/Test/FoldBlocks.hs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,33 @@
11
{-# LANGUAGE NamedFieldPuns #-}
2+
{-# LANGUAGE NumericUnderscores #-}
23
{-# LANGUAGE OverloadedStrings #-}
34
{-# LANGUAGE TupleSections #-}
45

56
module Cardano.Testnet.Test.FoldBlocks where
67

78
import Cardano.Api hiding (cardanoEra)
89
import qualified Cardano.Api as Api
9-
import Cardano.Api.Error (displayError)
10+
import Cardano.Api.Error
1011
import qualified Cardano.Api.Shelley as Api
1112

1213
import Cardano.Testnet as TN
1314

15+
import Prelude
16+
1417
import qualified Control.Concurrent as IO
1518
import Control.Concurrent.Async (async, link)
1619
import Control.Exception (Exception, throw)
17-
import Control.Monad (forever)
20+
import Control.Monad
1821
import qualified System.Directory as IO
1922
import System.FilePath ((</>))
2023

2124
import qualified Testnet.Property.Utils as H
2225
import Testnet.Runtime
2326

2427
import qualified Hedgehog as H
25-
import qualified Hedgehog.Extras.Stock.IO.Network.Sprocket as HE
26-
import qualified Hedgehog.Extras.Test as HE
27-
import qualified Hedgehog.Extras.Test.Base as H
28+
import qualified Hedgehog.Extras.Stock.IO.Network.Sprocket as H
29+
import qualified Hedgehog.Extras.Test as H
30+
2831

2932
newtype FoldBlocksException = FoldBlocksException Api.FoldBlocksError
3033
instance Exception FoldBlocksException
@@ -50,7 +53,7 @@ prop_foldBlocks = H.integrationRetryWorkspace 2 "foldblocks" $ \tempAbsBasePath'
5053

5154
-- Get socketPath
5255
socketPathAbs <- do
53-
socketPath' <- HE.sprocketArgumentName <$> HE.headM (nodeSprocket . poolRuntime <$> poolNodes runtime)
56+
socketPath' <- H.sprocketArgumentName <$> H.headM (poolSprockets runtime)
5457
H.noteIO (IO.canonicalizePath $ tempAbsPath' </> socketPath')
5558

5659
-- Start foldBlocks in a separate thread
@@ -72,5 +75,6 @@ prop_foldBlocks = H.integrationRetryWorkspace 2 "foldblocks" $ \tempAbsBasePath'
7275
-- tests that `foldBlocks` receives ledger state; once that happens,
7376
-- handler is called, which then writes to the `lock` and allows the
7477
-- test to finish.
75-
_ <- H.evalIO $ IO.readMVar lock
78+
_ <- H.evalIO $ H.timeout 30_000_000 $ IO.readMVar lock
7679
H.assert True
80+
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
{-# LANGUAGE LambdaCase #-}
2+
{-# LANGUAGE NamedFieldPuns #-}
3+
{-# LANGUAGE OverloadedStrings #-}
4+
5+
module Cardano.Testnet.Test.LedgerEvents.TreasuryGrowth where
6+
7+
import Cardano.Api hiding (cardanoEra)
8+
import qualified Cardano.Api as Api
9+
import Cardano.Api.Ledger (Coin (..))
10+
11+
import qualified Cardano.Ledger.Shelley.LedgerState as L
12+
import Cardano.Testnet as TN
13+
14+
import Prelude
15+
16+
import Control.Monad.Trans.State.Strict
17+
import Data.List (sortOn)
18+
import Data.Map.Strict (Map)
19+
import qualified Data.Map.Strict as M
20+
import Lens.Micro ((^.))
21+
import qualified System.Directory as IO
22+
import System.FilePath ((</>))
23+
24+
import qualified Testnet.Property.Utils as H
25+
import Testnet.Runtime
26+
27+
import qualified Hedgehog as H
28+
import qualified Hedgehog.Extras.Stock.IO.Network.Sprocket as H
29+
import qualified Hedgehog.Extras.Test as H
30+
31+
32+
prop_check_if_treasury_is_growing :: H.Property
33+
prop_check_if_treasury_is_growing = H.integrationRetryWorkspace 0 "growing-treasury" $ \tempAbsBasePath' -> do
34+
-- Start testnet
35+
conf@Conf{tempAbsPath=TmpAbsolutePath tempAbsPath'} <- TN.mkConf tempAbsBasePath'
36+
37+
let era = BabbageEra
38+
options = cardanoDefaultTestnetOptions
39+
{ cardanoEpochLength = 100
40+
, cardanoNodeEra = AnyCardanoEra era -- TODO: We should only support the latest era and the upcoming era
41+
, cardanoActiveSlotsCoeff = 0.3
42+
}
43+
44+
runtime@TestnetRuntime{configurationFile} <- cardanoTestnetDefault options conf
45+
46+
-- uncomment for epoch state live access
47+
-- startLedgerNewEpochStateLogging runtime tempAbsBasePath'
48+
49+
-- Get socketPath
50+
socketPathAbs <- do
51+
socketPath' <- H.noteShowM $ H.sprocketArgumentName <$> H.headM (poolSprockets runtime)
52+
H.noteIO (IO.canonicalizePath $ tempAbsPath' </> socketPath')
53+
54+
(_condition, treasuryValues) <- H.leftFailM . runExceptT $
55+
Api.foldEpochState (File configurationFile) (Api.File socketPathAbs) Api.QuickValidation 10 M.empty handler
56+
H.note_ $ "treasury for last 5 epochs: " <> show treasuryValues
57+
58+
let treasuriesSortedByEpoch =
59+
map snd
60+
. sortOn fst
61+
. M.assocs
62+
$ treasuryValues
63+
64+
if checkNonDecreasing treasuriesSortedByEpoch && checkHasIncreased treasuriesSortedByEpoch
65+
then H.success
66+
else do
67+
H.note_ "treasury is not growing"
68+
H.failure
69+
where
70+
handler :: AnyNewEpochState -> StateT (Map EpochNo Integer) IO LedgerStateCondition
71+
handler (AnyNewEpochState _ newEpochState) = do
72+
let (Coin coin) = newEpochState ^. L.nesEsL . L.esAccountStateL . L.asTreasuryL
73+
epochNo = newEpochState ^. L.nesELL
74+
-- handler is executed multiple times per epoch, so we keep only the latest treasury value
75+
modify $ M.insert epochNo coin
76+
if epochNo >= EpochNo 5
77+
then pure ConditionMet
78+
else pure ConditionNotMet
79+
80+
-- | Check if the last element > first element
81+
checkHasIncreased :: (Ord a) => [a] -> Bool
82+
checkHasIncreased = \case
83+
[] -> False
84+
x1:xs -> case reverse xs of
85+
[] -> False
86+
xn:_ -> xn > x1
87+
88+
checkNonDecreasing :: (Ord a) => [a] -> Bool
89+
checkNonDecreasing = \case
90+
[] -> False
91+
[_] -> True
92+
(x:y:xs) -> x <= y && checkNonDecreasing (y:xs)
93+

cardano-testnet/test/cardano-testnet-test/cardano-testnet-test.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import qualified Cardano.Testnet.Test.Cli.QuerySlotNumber
1515
import qualified Cardano.Testnet.Test.FoldBlocks
1616
import qualified Cardano.Testnet.Test.LedgerEvents.Gov.ProposeNewConstitutionSPO as LedgerEvents
1717
import qualified Cardano.Testnet.Test.LedgerEvents.SanityCheck as LedgerEvents
18+
import qualified Cardano.Testnet.Test.LedgerEvents.TreasuryGrowth as LedgerEvents
1819
import qualified Cardano.Testnet.Test.Node.Shutdown
1920
import qualified Cardano.Testnet.Test.SubmitApi.Babbage.Transaction
2021

@@ -36,6 +37,7 @@ tests = do
3637
[ testGroup "Spec"
3738
[ testGroup "Ledger Events"
3839
[ H.ignoreOnWindows "Sanity Check" LedgerEvents.hprop_ledger_events_sanity_check
40+
, H.ignoreOnWindows "Treasury Growth" LedgerEvents.prop_check_if_treasury_is_growing
3941
-- TODO: Replace foldBlocks with checkLedgerStateCondition
4042
, testGroup "Governance"
4143
-- FIXME Those tests are flaky

0 commit comments

Comments
 (0)