Skip to content
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

Report error on unsupported era #1219

Merged
merged 38 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c83adaf
Add test stub for surviving a conway fork
locallycompact Dec 13, 2023
bc7c41a
Draft era mismatch e2e test and configurable Devnet setup
ch1bo Dec 14, 2023
852f355
Resolve TODO for setting up cardano node in devnet
ffakenz Dec 14, 2023
62e2469
Remove unnecessary config from default
ffakenz Dec 14, 2023
e0c3d12
Change default cardano node config file name to match ours
ffakenz Dec 14, 2023
2d98b3f
Implement forkIntoConwayInEpoch function
ffakenz Dec 14, 2023
8f64c76
fix forkIntoConwayInEpoch by passing the stateDirectory to find the c…
ffakenz Dec 14, 2023
a7ef7ec
Add genDelegs to genesis-conway as it is needed for cardano-node to run
ffakenz Dec 14, 2023
bfb796d
Make stderr configurable in withHydraNode
locallycompact Dec 14, 2023
a7977c0
Fetch slotLength and epochLength from args
ffakenz Dec 15, 2023
07bb345
Introduce ChainClientException and try to catch it as part of e2e
ffakenz Dec 18, 2023
3dacdf1
Fix end-to-end test on non-supported cardano era
ch1bo Dec 19, 2023
74f4dc1
Use displayException in hydra-node to explain EraNotSupportedException
ch1bo Dec 19, 2023
1e37e59
Draft another e2e test about node failing on incorrect era
ch1bo Dec 19, 2023
cd63e5a
Fix e2e spec to report on startup
ffakenz Dec 19, 2023
fcc24c7
Minor formatting changes
ffakenz Dec 19, 2023
ad88952
Migrate configuration exceptions to use displayException to explain
ffakenz Dec 19, 2023
5a019ff
Update CHANGELOG
ffakenz Dec 19, 2023
c34532f
Update explain messages for not supported era exceptions
ffakenz Dec 19, 2023
1443e45
Improve getField helper function by using lenses
ffakenz Dec 20, 2023
c00ca7e
Reduce epochLengh even further to speedup tests depending on it
ffakenz Dec 20, 2023
d383b8c
Apply review changes
ffakenz Dec 20, 2023
0005a09
Remove stderr to be configurable in withHydraNode, as not needed
ffakenz Dec 20, 2023
dc38469
Revert cabal.project changes in code
ffakenz Dec 21, 2023
63a8e79
Minor fix to error output assertions
ffakenz Dec 21, 2023
eb25cb0
Remove addField helper, use aeson-lenses instead
ffakenz Dec 21, 2023
91d4c19
Improve era missmatch error messages
ffakenz Dec 21, 2023
92247a1
Enhance error msg for EraNotSupportedException
ffakenz Dec 21, 2023
a8dceda
Update fourmolu fixities to match treefmt rules
ffakenz Dec 21, 2023
d45ff93
Minor haddock fix
ffakenz Dec 21, 2023
4341484
Remove getField helper, use aeson-lenses instead
ffakenz Dec 21, 2023
ed41f2d
Minor formatting changes
ffakenz Dec 21, 2023
c1ffcb5
Improved delayEpoch so it waits until it reaches the target epoch
ffakenz Dec 22, 2023
3b458e3
Revert "Update fourmolu fixities to match treefmt rules"
ffakenz Dec 22, 2023
7b1b1c6
Minor formatting changes
ffakenz Dec 22, 2023
a22e308
Fix formatting for <&> in presence of ?~
ch1bo Dec 22, 2023
46d0f1b
Remove commented code
ffakenz Dec 22, 2023
a67ec3e
Improve error messages by using printf
ffakenz Dec 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ changes.
- Hydra.Options split into Hydra.Options.Common, Hydra.Options.Offline,
Hydra.Options.Online, re-exported from Hydra.Options.

- Report error on unsupported era.

## [0.14.0] - 2023-12-04

Expand Down
1 change: 1 addition & 0 deletions fourmolu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ fixities:
- infixr 1 &
- infixl 3 <|>
- infixr 3 &&
- infixl 1 <&>
2 changes: 1 addition & 1 deletion hydra-cluster/bench/Bench/EndToEnd.hs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ commitUTxO node clients Dataset{clientDatasets} =
doCommit (client, ClientDataset{initialUTxO, clientKeys = ClientKeys{externalSigningKey}}) = do
requestCommitTx client initialUTxO
<&> signTx externalSigningKey
>>= submitTx node
>>= submitTx node
pure initialUTxO

processTransactions :: [HydraClient] -> Dataset -> IO (Map.Map TxId Event)
Expand Down
1 change: 1 addition & 0 deletions hydra-cluster/config/devnet/genesis-conway.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"genDelegs": {},
"poolVotingThresholds": {
"pvtCommitteeNormal": 0.51,
"pvtCommitteeNoConfidence": 0.51,
Expand Down
2 changes: 1 addition & 1 deletion hydra-cluster/config/devnet/genesis-shelley.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"epochLength": 432000,
"epochLength": 5,
"activeSlotsCoeff": 1.0,
"slotLength": 0.1,
"securityParam": 2160,
Expand Down
148 changes: 81 additions & 67 deletions hydra-cluster/src/CardanoNode.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ module CardanoNode where

import Hydra.Prelude

import Control.Lens ((^?!))
import Control.Lens ((?~), (^?!))
import Control.Tracer (Tracer, traceWith)
import Data.Aeson ((.=))
import Data.Aeson (Value (String), (.=))
import Data.Aeson qualified as Aeson
import Data.Aeson.KeyMap qualified as Aeson.KeyMap
import Data.Aeson.Lens (key, _Number)
import Data.Aeson.Lens (atKey, key, _Number)
import Data.Fixed (Centi)
import Data.Text qualified as Text
import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds)
import Hydra.Cardano.Api (AsType (AsPaymentKey), File (..), NetworkId, PaymentKey, SigningKey, SocketPath, VerificationKey, generateSigningKey, getVerificationKey)
import Hydra.Cardano.Api qualified as Api
Expand Down Expand Up @@ -77,7 +77,7 @@ defaultCardanoNodeArgs :: CardanoNodeArgs
defaultCardanoNodeArgs =
CardanoNodeArgs
{ nodeSocket = "node.socket"
, nodeConfigFile = "configuration.json"
, nodeConfigFile = "cardano-node.json"
, nodeByronGenesisFile = "genesis-byron.json"
, nodeShelleyGenesisFile = "genesis-shelley.json"
, nodeAlonzoGenesisFile = "genesis-alonzo.json"
Expand Down Expand Up @@ -117,64 +117,14 @@ withCardanoNodeDevnet ::
(RunningNode -> IO a) ->
IO a
withCardanoNodeDevnet tracer stateDirectory action = do
createDirectoryIfMissing True stateDirectory
[dlgCert, signKey, vrfKey, kesKey, opCert] <-
mapM
copyDevnetCredential
[ "byron-delegation.cert"
, "byron-delegate.key"
, "vrf.skey"
, "kes.skey"
, "opcert.cert"
]
let args =
defaultCardanoNodeArgs
{ nodeDlgCertFile = Just dlgCert
, nodeSignKeyFile = Just signKey
, nodeVrfKeyFile = Just vrfKey
, nodeKesKeyFile = Just kesKey
, nodeOpCertFile = Just opCert
}
copyDevnetFiles args
refreshSystemStart stateDirectory args
writeTopology [] args

args <- setupCardanoDevnet stateDirectory
withCardanoNode tracer networkId stateDirectory args $ \rn -> do
traceWith tracer MsgNodeIsReady
action rn
where
-- NOTE: This needs to match what's in config/genesis-shelley.json
networkId = defaultNetworkId

copyDevnetCredential file = do
let destination = stateDirectory </> file
unlessM (doesFileExist destination) $
readConfigFile ("devnet" </> file)
>>= writeFileBS destination
setFileMode destination ownerReadMode
pure file

copyDevnetFiles args = do
readConfigFile ("devnet" </> "cardano-node.json")
>>= writeFileBS
(stateDirectory </> nodeConfigFile args)
readConfigFile ("devnet" </> "genesis-byron.json")
>>= writeFileBS
(stateDirectory </> nodeByronGenesisFile args)
readConfigFile ("devnet" </> "genesis-shelley.json")
>>= writeFileBS
(stateDirectory </> nodeShelleyGenesisFile args)
readConfigFile ("devnet" </> "genesis-alonzo.json")
>>= writeFileBS
(stateDirectory </> nodeAlonzoGenesisFile args)
readConfigFile ("devnet" </> "genesis-conway.json")
>>= writeFileBS
(stateDirectory </> nodeConwayGenesisFile args)

writeTopology peers args =
Aeson.encodeFile (stateDirectory </> nodeTopologyFile args) $
mkTopology peers

-- | Run a cardano-node as normal network participant on a known network.
withCardanoNodeOnKnownNetwork ::
Tracer IO NodeLog ->
Expand Down Expand Up @@ -205,7 +155,7 @@ withCardanoNodeOnKnownNetwork tracer workDir knownNetwork action = do
readNetworkId = do
shelleyGenesis :: Aeson.Value <- unsafeDecodeJson =<< readFileBS (workDir </> "shelley-genesis.json")
if shelleyGenesis ^?! key "networkId" == "Mainnet"
then pure $ Api.Mainnet
then pure Api.Mainnet
else do
let magic = shelleyGenesis ^?! key "networkMagic" . _Number
pure $ Api.Testnet (Api.NetworkMagic $ truncate magic)
Expand Down Expand Up @@ -241,6 +191,73 @@ withCardanoNodeOnKnownNetwork tracer workDir knownNetwork action = do
fetchConfigFile path =
parseRequestThrow path >>= httpBS <&> getResponseBody

-- | Setup the cardano-node to run a local devnet producing blocks. This copies
-- the appropriate files and prepares 'CardanoNodeArgs' for 'withCardanoNode'.
setupCardanoDevnet :: FilePath -> IO CardanoNodeArgs
setupCardanoDevnet stateDirectory = do
createDirectoryIfMissing True stateDirectory
[dlgCert, signKey, vrfKey, kesKey, opCert] <-
mapM
copyDevnetCredential
[ "byron-delegation.cert"
, "byron-delegate.key"
, "vrf.skey"
, "kes.skey"
, "opcert.cert"
]
let args =
defaultCardanoNodeArgs
{ nodeDlgCertFile = Just dlgCert
, nodeSignKeyFile = Just signKey
, nodeVrfKeyFile = Just vrfKey
, nodeKesKeyFile = Just kesKey
, nodeOpCertFile = Just opCert
}
copyDevnetFiles args
refreshSystemStart stateDirectory args
writeTopology [] args
pure args
where
copyDevnetCredential file = do
let destination = stateDirectory </> file
unlessM (doesFileExist destination) $
readConfigFile ("devnet" </> file)
>>= writeFileBS destination
setFileMode destination ownerReadMode
pure file

copyDevnetFiles args = do
readConfigFile ("devnet" </> "cardano-node.json")
>>= writeFileBS
(stateDirectory </> nodeConfigFile args)
readConfigFile ("devnet" </> "genesis-byron.json")
>>= writeFileBS
(stateDirectory </> nodeByronGenesisFile args)
readConfigFile ("devnet" </> "genesis-shelley.json")
>>= writeFileBS
(stateDirectory </> nodeShelleyGenesisFile args)
readConfigFile ("devnet" </> "genesis-alonzo.json")
>>= writeFileBS
(stateDirectory </> nodeAlonzoGenesisFile args)
readConfigFile ("devnet" </> "genesis-conway.json")
>>= writeFileBS
(stateDirectory </> nodeConwayGenesisFile args)

writeTopology peers args =
Aeson.encodeFile (stateDirectory </> nodeTopologyFile args) $
mkTopology peers

-- | Modify the cardano-node configuration to fork into conway at given era
-- number.
forkIntoConwayInEpoch :: FilePath -> CardanoNodeArgs -> Natural -> IO ()
forkIntoConwayInEpoch stateDirectory args n = do
config <-
unsafeDecodeJsonFile @Aeson.Value (stateDirectory </> nodeConfigFile args)
<&> atKey "TestConwayHardForkAtEpoch" ?~ toJSON n
Aeson.encodeFile
(stateDirectory </> nodeConfigFile args)
config

withCardanoNode ::
Tracer IO NodeLog ->
NetworkId ->
Expand Down Expand Up @@ -341,19 +358,19 @@ refreshSystemStart stateDirectory args = do
systemStart <- initSystemStart
let startTime = round @_ @Int $ utcTimeToPOSIXSeconds systemStart
byronGenesis <-
unsafeDecodeJsonFile (stateDirectory </> nodeByronGenesisFile args)
<&> addField "startTime" startTime
unsafeDecodeJsonFile @Aeson.Value (stateDirectory </> nodeByronGenesisFile args)
<&> atKey "startTime" ?~ toJSON startTime

let systemStartUTC =
posixSecondsToUTCTime . fromRational . toRational $ startTime
shelleyGenesis <-
unsafeDecodeJsonFile (stateDirectory </> nodeShelleyGenesisFile args)
<&> addField "systemStart" systemStartUTC
unsafeDecodeJsonFile @Aeson.Value (stateDirectory </> nodeShelleyGenesisFile args)
<&> atKey "systemStart" ?~ toJSON systemStartUTC

config <-
unsafeDecodeJsonFile (stateDirectory </> nodeConfigFile args)
<&> addField "ByronGenesisFile" (nodeByronGenesisFile args)
<&> addField "ShelleyGenesisFile" (nodeShelleyGenesisFile args)
unsafeDecodeJsonFile @Aeson.Value (stateDirectory </> nodeConfigFile args)
<&> (atKey "ByronGenesisFile" ?~ toJSON (Text.pack $ nodeByronGenesisFile args))
. (atKey "ShelleyGenesisFile" ?~ String (Text.pack $ nodeShelleyGenesisFile args))

Aeson.encodeFile
(stateDirectory </> nodeByronGenesisFile args)
Expand Down Expand Up @@ -402,9 +419,6 @@ data NodeLog
-- Helpers
--

addField :: ToJSON a => Aeson.Key -> a -> Aeson.Value -> Aeson.Value
addField k v = withObject (Aeson.KeyMap.insert k (toJSON v))

-- | Do something with an a JSON object. Fails if the given JSON value isn't an
-- object.
withObject :: (Aeson.Object -> Aeson.Object) -> Aeson.Value -> Aeson.Value
Expand Down
16 changes: 8 additions & 8 deletions hydra-cluster/src/HydraNode.hs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ withHydraNode ::
withHydraNode tracer chainConfig workDir hydraNodeId hydraSKey hydraVKeys allNodeIds hydraScriptsTxId action = do
withLogFile logFilePath $ \logFileHandle -> do
withHydraNode' chainConfig workDir hydraNodeId hydraSKey hydraVKeys allNodeIds hydraScriptsTxId (Just logFileHandle) $ do
\_ processHandle -> do
\_ _ processHandle -> do
race
(checkProcessHasNotDied ("hydra-node (" <> show hydraNodeId <> ")") processHandle)
(withConnectionToNode tracer hydraNodeId action)
Expand All @@ -388,7 +388,7 @@ withHydraNode' ::
TxId ->
-- | If given use this as std out.
Maybe Handle ->
(Handle -> ProcessHandle -> IO a) ->
(Handle -> Handle -> ProcessHandle -> IO a) ->
IO a
withHydraNode' chainConfig workDir hydraNodeId hydraSKey hydraVKeys allNodeIds hydraScriptsTxId mGivenStdOut action = do
withSystemTempDirectory "hydra-node" $ \dir -> do
Expand Down Expand Up @@ -423,13 +423,13 @@ withHydraNode' chainConfig workDir hydraNodeId hydraSKey hydraVKeys allNodeIds h
}
)
{ std_out = maybe CreatePipe UseHandle mGivenStdOut
, std_err = Inherit
, std_err = CreatePipe
}
withCreateProcess p $ \_stdin mCreatedHandle mErr processHandle ->
case (mCreatedHandle, mGivenStdOut, mErr) of
(Just out, _, _) -> action out processHandle
(Nothing, Just out, _) -> action out processHandle
(_, _, _) -> error "Should not happen™"
withCreateProcess p $ \_stdin mCreatedStdOut mCreatedStdErr processHandle ->
case (mCreatedStdOut <|> mGivenStdOut, mCreatedStdErr) of
(Just out, Just err) -> action out err processHandle
(Nothing, _) -> error "Should not happen™"
(_, Nothing) -> error "Should not happen™"
where
peers =
[ Host
Expand Down
Loading
Loading