content: {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE NamedFieldPuns #-}
  {-# LANGUAGE NumericUnderscores #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TypeApplications #-}
  
  module Cardano.Testnet.Test.Gov.GovActionTimeout
    ( hprop_check_gov_action_timeout
    ) where
  
  import           Cardano.Api as Api
  import           Cardano.Api.Ledger (EpochInterval (..))
  
  import           Cardano.Testnet
  
  import           Prelude
  
  import           Control.Monad (void)
  import           Data.Default.Class
  import qualified Data.Text as Text
  import           System.FilePath ((</>))
  
  import           Testnet.Components.Query
  import           Testnet.Process.Cli.DRep (makeActivityChangeProposal)
  import           Testnet.Process.Cli.Keys (cliStakeAddressKeyGen)
  import           Testnet.Process.Cli.SPO (createStakeKeyRegistrationCertificate)
  import           Testnet.Process.Run (execCli', mkExecConfig)
  import           Testnet.Property.Util (integrationRetryWorkspace)
  import           Testnet.Start.Types
  import           Testnet.Types
  
  import           Hedgehog (Property)
  import qualified Hedgehog as H
  import qualified Hedgehog.Extras as H
  
  -- | Test that SPOs cannot vote on a Protocol Parameter change
  -- | Execute me with:
  -- @DISABLE_RETRIES=1 cabal test cardano-testnet-test --test-options '-p "/Gov Action Timeout/"'@
  hprop_check_gov_action_timeout :: Property
  hprop_check_gov_action_timeout = integrationRetryWorkspace 2 "gov-action-timeout" $ \tempAbsBasePath' ->
                                   H.runWithDefaultWatchdog_ $ do
    -- Start a local test net
    conf@Conf { tempAbsPath } <- mkConf tempAbsBasePath'
    let tempAbsPath' = unTmpAbsPath tempAbsPath
        tempBaseAbsPath = makeTmpBaseAbsPath tempAbsPath
  
    work <- H.createDirectoryIfMissing $ tempAbsPath' </> "work"
  
    -- Create default testnet
    let ceo = ConwayEraOnwardsConway
        sbe = convert ceo
        eraName = eraToString sbe
        asbe = AnyShelleyBasedEra sbe
        fastTestnetOptions = def { cardanoNodeEra = asbe }
        shelleyOptions = def { genesisEpochLength = 200 }
  
    TestnetRuntime
      { testnetMagic
      , testnetNodes
      , wallets=wallet0:wallet1:_
      , configurationFile
      }
      <- createAndRunTestnet fastTestnetOptions shelleyOptions conf
  
    node <- H.headM testnetNodes
    poolSprocket1 <- H.noteShow $ nodeSprocket node
    execConfig <- mkExecConfig tempBaseAbsPath poolSprocket1 testnetMagic
    let socketPath = nodeSocketPath node
  
    epochStateView <- getEpochStateView configurationFile socketPath
  
    H.note_ $ "Sprocket: " <> show poolSprocket1
    H.note_ $ "Abs path: " <> tempAbsBasePath'
    H.note_ $ "Socketpath: " <> unFile socketPath
    H.note_ $ "Foldblocks config file: " <> unFile configurationFile
  
    gov <- H.createDirectoryIfMissing $ work </> "governance"
  
    baseDir <- H.createDirectoryIfMissing $ gov </> "output"
  
    -- Figure out expiration time for proposals
  
    govActionLifetime <- getGovActionLifetime epochStateView ceo
    H.note_ $ "govActionLifetime: " <> show govActionLifetime
  
    -- Register stake address
    let stakeCertFp = gov </> "stake.regcert"
        stakeKeys =  KeyPair { verificationKey = File $ gov </> "stake.vkey"
                             , signingKey = File $ gov </> "stake.skey"
                             }
    cliStakeAddressKeyGen stakeKeys
    keyDeposit <- getKeyDeposit epochStateView ceo
    createStakeKeyRegistrationCertificate
      tempAbsPath (AnyShelleyBasedEra sbe) (verificationKey stakeKeys) keyDeposit stakeCertFp
  
  
    stakeCertTxBodyFp <- H.note $ work </> "stake.registration.txbody"
    stakeCertTxSignedFp <- H.note $ work </> "stake.registration.tx"
  
    txin1 <- findLargestUtxoForPaymentKey epochStateView sbe wallet1
  
    void $ execCli' execConfig
      [ eraName, "transaction", "build"
      , "--change-address", Text.unpack $ paymentKeyInfoAddr wallet1
      , "--tx-in", Text.unpack $ renderTxIn txin1
      , "--tx-out", Text.unpack (paymentKeyInfoAddr wallet1) <> "+" <> show @Int 10_000_000
      , "--certificate-file", stakeCertFp
      , "--witness-override", show @Int 2
      , "--out-file", stakeCertTxBodyFp
      ]
  
    void $ execCli' execConfig
      [ eraName, "transaction", "sign"
      , "--tx-body-file", stakeCertTxBodyFp
      , "--signing-key-file", signingKeyFp $ paymentKeyInfoPair wallet1
      , "--signing-key-file", signingKeyFp stakeKeys
      , "--out-file", stakeCertTxSignedFp
      ]
  
    void $ execCli' execConfig
      [ eraName, "transaction", "submit"
      , "--tx-file", stakeCertTxSignedFp
      ]
  
    -- make sure that stake registration cert gets into a block
    _ <- waitForBlocks epochStateView 1
  
    -- Create a proposal
    (governanceActionTxId, _governanceActionIndex) <-
      makeActivityChangeProposal execConfig epochStateView ceo (baseDir </> "proposal")
                                 Nothing (EpochInterval 3) stakeKeys wallet0 (EpochInterval 2)
  
    -- Wait for proposal to expire
    void $ waitForEpochs epochStateView (EpochInterval $ unEpochInterval govActionLifetime + 1)
  
    -- Check proposal expired
    mGovernanceActionTxIx <- watchEpochStateUpdate epochStateView (EpochInterval 2) $ \(anyNewEpochState, _, _) ->
        return $ maybeExtractGovernanceActionIndex governanceActionTxId anyNewEpochState
  
    mGovernanceActionTxIx H.=== Nothing
  
  