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

Fix decoding of Hydra keys and ignore problematic head init #1857

Merged
merged 2 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 9 additions & 2 deletions hydra-tx/src/Hydra/Tx/Crypto.hs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import Hydra.Cardano.Api (
Key (..),
SerialiseAsCBOR,
SerialiseAsRawBytes (..),
SerialiseAsRawBytesError (..),
serialiseToRawBytesHexText,
)
import Hydra.Contract.HeadState qualified as OnChain
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion hydra-tx/src/Hydra/Tx/Init.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ data InitObservation = InitObservation
data NotAnInitReason
= NoHeadOutput
| NotAHeadDatum
| InvalidPartyInDatum
| NoSTFound
| NotAHeadPolicy
deriving stock (Show, Eq, Generic)
Expand Down Expand Up @@ -131,14 +132,18 @@ observeInitTx tx = do
unless (pid == HeadTokens.headPolicyId seedTxIn) $
Left NotAHeadPolicy

parties <-
maybe (Left InvalidPartyInDatum) Right $
traverse partyFromChain onChainParties

pure $
InitObservation
{ headId = mkHeadId pid
, seedTxIn
, initialThreadUTxO = (mkTxIn tx ix, toCtxUTxOTxOut headOut)
, initials
, contestationPeriod
, parties = mapMaybe partyFromChain onChainParties
, parties
, participants = assetNameToOnChainId <$> mintedTokenNames pid
}
where
Expand Down
4 changes: 4 additions & 0 deletions hydra-tx/src/Hydra/Tx/Observe.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down