From b37a7b2d888c860d8343f665a8f6311ed39538b7 Mon Sep 17 00:00:00 2001 From: Sebastian Nagel Date: Fri, 14 Feb 2025 14:37:47 +0100 Subject: [PATCH 1/2] Fix decoding of Hydra keys and ignore problematic head init We were not correctly decoding Hydra verification keys (but crashing via error) because of a missing data constructor. This also makes the observeInitTx sort out heads that would have such problematic party datums. An example transaction with problematic data is: b860a236a7e77577628bf705286d449188831cf90d714934f1cc06369c6e3953 on preprod --- hydra-tx/src/Hydra/Tx/Crypto.hs | 11 +++++++++-- hydra-tx/src/Hydra/Tx/Init.hs | 7 ++++++- hydra-tx/src/Hydra/Tx/Observe.hs | 4 ++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hydra-tx/src/Hydra/Tx/Crypto.hs b/hydra-tx/src/Hydra/Tx/Crypto.hs index 57e59f7be98..4d5decb0cc2 100644 --- a/hydra-tx/src/Hydra/Tx/Crypto.hs +++ b/hydra-tx/src/Hydra/Tx/Crypto.hs @@ -56,6 +56,7 @@ import Hydra.Cardano.Api ( Key (..), SerialiseAsCBOR, SerialiseAsRawBytes (..), + SerialiseAsRawBytesError (..), serialiseToRawBytesHexText, ) import Hydra.Contract.HeadState qualified as OnChain @@ -83,7 +84,10 @@ instance SerialiseAsRawBytes (Hash HydraKey) where serialiseToRawBytes (HydraKeyHash vkh) = hashToBytes vkh deserialiseFromRawBytes (AsHash AsHydraKey) bs = - maybe (error "TODO: SerialiseAsRawBytesError, but constructor not exported") (Right . HydraKeyHash) (hashFromBytes bs) + maybe + (Left $ SerialiseAsRawBytesError "invalid length when deserializing Hash HydraKey") + (Right . HydraKeyHash) + (hashFromBytes bs) instance Key HydraKey where -- Hydra verification key, which can be used to 'verify' signed messages. @@ -140,7 +144,10 @@ instance SerialiseAsRawBytes (VerificationKey HydraKey) where rawSerialiseVerKeyDSIGN vk deserialiseFromRawBytes (AsVerificationKey AsHydraKey) bs = - maybe (error "TODO: SerialiseAsRawBytesError, but constructor not exported") (Right . HydraVerificationKey) (rawDeserialiseVerKeyDSIGN bs) + maybe + (Left $ SerialiseAsRawBytesError "invalid length when deserializing VerificationKey HydraKey") + (Right . HydraVerificationKey) + (rawDeserialiseVerKeyDSIGN bs) instance ToJSON (VerificationKey HydraKey) where toJSON = toJSON . serialiseToRawBytesHexText diff --git a/hydra-tx/src/Hydra/Tx/Init.hs b/hydra-tx/src/Hydra/Tx/Init.hs index c499a59d350..af2ba933873 100644 --- a/hydra-tx/src/Hydra/Tx/Init.hs +++ b/hydra-tx/src/Hydra/Tx/Init.hs @@ -99,6 +99,7 @@ data InitObservation = InitObservation data NotAnInitReason = NoHeadOutput | NotAHeadDatum + | InvalidPartyInDatum | NoSTFound | NotAHeadPolicy deriving stock (Show, Eq, Generic) @@ -131,6 +132,10 @@ observeInitTx tx = do unless (pid == HeadTokens.headPolicyId seedTxIn) $ Left NotAHeadPolicy + parties <- + maybe (Left InvalidPartyInDatum) Right $ + traverse partyFromChain onChainParties + pure $ InitObservation { headId = mkHeadId pid @@ -138,7 +143,7 @@ observeInitTx tx = do , initialThreadUTxO = (mkTxIn tx ix, toCtxUTxOTxOut headOut) , initials , contestationPeriod - , parties = mapMaybe partyFromChain onChainParties + , parties , participants = assetNameToOnChainId <$> mintedTokenNames pid } where diff --git a/hydra-tx/src/Hydra/Tx/Observe.hs b/hydra-tx/src/Hydra/Tx/Observe.hs index a048805595c..ec06eb7c3cc 100644 --- a/hydra-tx/src/Hydra/Tx/Observe.hs +++ b/hydra-tx/src/Hydra/Tx/Observe.hs @@ -53,6 +53,10 @@ data HeadObservation -- | Observe any Hydra head transaction. observeHeadTx :: NetworkId -> UTxO -> Tx -> HeadObservation observeHeadTx networkId utxo tx = + -- XXX: This is throwing away valuable information! We should be collecting + -- all "not an XX" reasons here in case we fall through and want that + -- diagnostic information in the call site of this function. Collecting errors + -- could be done with 'validation' or a similar package. fromMaybe NoHeadTx $ either (const Nothing) (Just . Init) (observeInitTx tx) <|> Abort <$> observeAbortTx utxo tx From 98f33f455b606667205cd44bbd7672d34a510a4c Mon Sep 17 00:00:00 2001 From: Sebastian Nagel Date: Fri, 14 Feb 2025 14:49:22 +0100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccb336fcdd0..509a7325ce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ changes. ## [0.20.1] - UNRELEASED +- Fix a bug where decoding `Party` information from chain would crash the node + or chain observer. A problematic transaction will now be ignored and not + deemed a valid head protocol transaction. An example was if the datum would + contain CBOR instead of just hex encoded bytes. + - Stream historical data from disk in the hydra-node API server. - Record used and free memory when running `bench-e2e` benchmark.