Skip to content

Commit

Permalink
Babbage backward compatibility (#1608)
Browse files Browse the repository at this point in the history
Ensures that transactions decoded from JSON are backwards compatibility
with `Babbage`.

* Moves tests to `hydra-tx` as it contains the instance definitions. 
* Adds tests for backward compatibility with explicitly Babbage.
* Drops the check of `type` in the "Transaction envelope".
 
---

<!-- Consider each and tick it off one way or the other -->
* [x] CHANGELOG updated
* [x] Documentation update not needed
* [x] Haddocks updated
* [x] No new TODOs introduced
  • Loading branch information
noonio authored Sep 10, 2024
2 parents 382512c + cfd24ec commit d4b3cbc
Show file tree
Hide file tree
Showing 15 changed files with 2,562 additions and 2,699 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
As a minor extension, we also keep a semantic version for the `UNRELEASED`
changes.

## [0.18.2] - UNRELEASED
## [0.19.0] - UNRELEASED

- Switch L2 ledger to use the `Conway` era. [#1178](https://github.com/cardano-scaling/hydra/issues/1178)
- Conway formatted transactions can be submitted to the `hydra-node`, while past eras are still supported (except deprecated features like protocol updates).
- This includes support for `PlutusV3` scripts, but most of the governance-related features have no meaning in the Hydra L2.

- Adds a manual recipient address entry to `hydra-tui` and fixes event handling. [#1607](https://github.com/cardano-scaling/hydra/pull/1607)

Expand Down
2 changes: 1 addition & 1 deletion hydra-cardano-api/src/Hydra/Cardano/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ import Hydra.Cardano.Api.ReferenceScript as Extras
import Hydra.Cardano.Api.ScriptData as Extras
import Hydra.Cardano.Api.ScriptDatum as Extras
import Hydra.Cardano.Api.ScriptHash as Extras
import Hydra.Cardano.Api.Tx as Extras
import Hydra.Cardano.Api.Tx as Extras hiding (Tx)
import Hydra.Cardano.Api.TxBody as Extras
import Hydra.Cardano.Api.TxId as Extras
import Hydra.Cardano.Api.TxIn as Extras
Expand Down
9 changes: 8 additions & 1 deletion hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
module Hydra.Cardano.Api.Tx where
module Hydra.Cardano.Api.Tx (
-- * Extras
module Hydra.Cardano.Api.Tx,

-- * Re-export normal Tx (any era)
Tx,
)
where

import Hydra.Cardano.Api.Prelude

Expand Down
2 changes: 1 addition & 1 deletion hydra-node/golden/StateChanged/DecommitRecorded.json

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions hydra-node/golden/StateChanged/SnapshotRequested.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion hydra-node/golden/StateChanged/TransactionReceived.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions hydra-node/hydra-node.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: hydra-node
version: 0.18.1
version: 0.19.0
synopsis: The Hydra node
author: IOG
copyright: 2022 IOG
Expand Down Expand Up @@ -318,7 +318,6 @@ test-suite tests
build-depends:
, aeson
, base
, base16-bytestring
, bytestring
, cardano-binary
, cardano-crypto-class
Expand Down
10 changes: 10 additions & 0 deletions hydra-node/json-schemas/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1982,6 +1982,16 @@ components:
- cborHex
- description
- type
description: |
A Cardano transaction in the text envelope format . That is, a JSON
object wrapper with some 'type' around a 'cborHex' encoded transaction.
The hydra-node uses this format as follows:
- When encoding, an additonal 'txId' is included.
- On decoding, when 'txId' is included it is checked to be consistent.
- The 'type' is not used to determine content and any transaction is
tried to decode as a 'ConwayEra' transaction, which mostly is
backward compatible to previous eras.
properties:
type:
type: string
Expand Down
57 changes: 2 additions & 55 deletions hydra-node/test/Hydra/Ledger/CardanoSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@

module Hydra.Ledger.CardanoSpec where

import Cardano.Api.UTxO (fromApi, toApi)
import Hydra.Cardano.Api
import Hydra.Prelude
import Test.Hydra.Prelude

import Cardano.Binary (decodeFull, serialize')
import Cardano.Ledger.Api (ensureMinCoinTxOut)
import Cardano.Ledger.Credential (Credential (..))
import Data.Aeson (eitherDecode, encode)
import Data.Aeson qualified as Aeson
import Data.Aeson.Lens (key)
import Data.ByteString.Base16 qualified as Base16
import Data.Text (unpack)
import Hydra.Cardano.Api.Pretty (renderTx)
import Hydra.Chain.ChainState (ChainSlot (ChainSlot))
Expand All @@ -24,23 +21,20 @@ import Hydra.Ledger.Cardano (
genSequenceOfSimplePaymentTransactions,
genTxOut,
)
import Hydra.Tx.IsTx (txId)
import Test.Aeson.GenericSpecs (roundtripAndGoldenSpecs)
import Test.Cardano.Ledger.Babbage.Arbitrary ()
import Test.Hydra.Node.Fixture (defaultGlobals, defaultLedgerEnv, defaultPParams)
import Test.Hydra.Tx.Gen (genOneUTxOFor, genOutput, genUTxOAdaOnlyOfSize, genUTxOAlonzo, genUTxOFor, genValue)
import Test.QuickCheck (Property, checkCoverage, conjoin, counterexample, cover, forAll, forAllBlind, property, sized, vectorOf, withMaxSuccess, (.&&.), (===))
import Test.QuickCheck (Property, checkCoverage, conjoin, counterexample, cover, forAll, forAllBlind, property, sized, vectorOf, withMaxSuccess, (===))
import Test.Util (propCollisionResistant)

spec :: Spec
spec =
parallel $ do
roundtripAndGoldenSpecs (Proxy @AssetName)
-- FIXME: Roundtrip instances for all JSON types we depend on

-- XXX: Move API conformance tests to API specs and add any missing ones
describe "UTxO" $ do
roundtripAndGoldenSpecs (Proxy @UTxO)

prop "JSON encoding of UTxO according to schema" $
prop_validateJSONSchema @UTxO "api.json" $
key "components" . key "schemas" . key "UTxO"
Expand All @@ -53,22 +47,10 @@ spec =
\ \"value\":{\"lovelace\":14}}}"
shouldParseJSONAs @UTxO bs

prop "Roundtrip to and from Api" roundtripFromAndToApi

describe "PParams" $
prop "Roundtrip JSON encoding" roundtripPParams

describe "Tx" $ do
roundtripAndGoldenSpecs (Proxy @(ReasonablySized Tx))

prop "Same TxId before/after JSON encoding" roundtripTxId

prop "Same TxId as TxBody after JSON decoding" roundtripTxId'

prop "Roundtrip to and from Ledger" roundtripLedger

prop "Roundtrip CBOR encoding" $ roundtripCBOR @Tx

prop "JSON encoding of Tx according to schema" $
withMaxSuccess 5 $
prop_validateJSONSchema @Tx "api.json" $
Expand Down Expand Up @@ -112,10 +94,6 @@ shouldParseJSONAs bs =
Left err -> failure err
Right (_ :: a) -> pure ()

roundtripFromAndToApi :: UTxO -> Property
roundtripFromAndToApi utxo =
fromApi (toApi utxo) === utxo

-- | Test that the 'PParams' To/FromJSON instances to roundtrip.
roundtripPParams :: PParams LedgerEra -> Property
roundtripPParams pparams = do
Expand All @@ -125,37 +103,6 @@ roundtripPParams pparams = do
Just actual ->
pparams === actual

roundtripTxId :: Tx -> Property
roundtripTxId tx@(Tx body _) =
case Aeson.decode (Aeson.encode tx) of
Nothing ->
property False
Just tx'@(Tx body' _) ->
(tx === tx' .&&. getTxId body === getTxId body')
& counterexample ("after: " <> decodeUtf8 (Base16.encode $ serialize' tx'))
& counterexample ("before: " <> decodeUtf8 (Base16.encode $ serialize' tx))

roundtripTxId' :: Tx -> Property
roundtripTxId' tx@(Tx body _) =
case Aeson.decode (Aeson.encode tx) of
Nothing ->
property False
Just tx'@(Tx body' _) ->
(txId tx === getTxId body' .&&. txId tx' == getTxId body)
& counterexample ("after: " <> decodeUtf8 (Base16.encode $ serialize' tx'))
& counterexample ("before: " <> decodeUtf8 (Base16.encode $ serialize' tx))

roundtripLedger :: Tx -> Property
roundtripLedger tx =
fromLedgerTx (toLedgerTx tx) === tx

roundtripCBOR :: (Eq a, Show a, ToCBOR a, FromCBOR a) => a -> Property
roundtripCBOR a =
let encoded = serialize' a
decoded = decodeFull $ fromStrict encoded
in decoded == Right a
& counterexample ("encoded: " <> show encoded <> ". decode: " <> show decoded)

appliesValidTransaction :: Property
appliesValidTransaction =
forAllBlind genSequenceOfSimplePaymentTransactions $ \(utxo, txs) ->
Expand Down
Loading

0 comments on commit d4b3cbc

Please sign in to comment.