import Hydra.Prelude hiding (label)
import Cardano.Api.UTxO as UTxO
-
import Cardano.Binary (serialize')
import Data.Maybe (fromJust)
-
import Hydra.Chain.Direct.Contract.Mutation (Mutation (..), SomeMutation (..), addParticipationTokens, changeHeadOutputDatum, genHash, replacePolicyIdWith)
+
import Hydra.Chain.Direct.Contract.Mutation (Mutation (..), SomeMutation (..), addParticipationTokens, changeHeadOutputDatum, genHash, replaceContestationDeadline, replaceHeadId, replaceParties, replacePolicyIdWith, replaceSnapshotNumber, replaceUtxoHash)
import Hydra.Chain.Direct.Fixture (genForParty, testNetworkId)
import qualified Hydra.Chain.Direct.Fixture as Fixture
+
import Hydra.Chain.Direct.TimeHandle (PointInTime)
import Hydra.Chain.Direct.Tx (ClosingSnapshot (..), OpenThreadOutput (..), UTxOHash (UTxOHash), closeTx, mkHeadId, mkHeadOutput)
import Hydra.ContestationPeriod (fromChain)
import qualified Hydra.Contract.HeadState as Head
import qualified Hydra.Data.Party as OnChain
import Hydra.Ledger (hashUTxO)
import Hydra.Ledger.Cardano (genOneUTxOFor, genVerificationKey)
-
import Hydra.Ledger.Cardano.Evaluate (genValidityBoundsFromContestationPeriod, slotNoToUTCTime)
+
import Hydra.Ledger.Cardano.Evaluate (genValidityBoundsFromContestationPeriod)
import Hydra.Party (Party, deriveParty, partyToChain)
import Hydra.Snapshot (Snapshot (..), SnapshotNumber)
-
import Plutus.V2.Ledger.Api (toBuiltin, toData)
+
import Plutus.V1.Ledger.Time (DiffMilliSeconds (..), fromMilliSeconds)
+
import Plutus.V2.Ledger.Api (BuiltinByteString, POSIXTime, toBuiltin, toData)
import Test.Hydra.Fixture (aliceSk, bobSk, carolSk)
import Test.QuickCheck (arbitrarySizedNatural, choose, elements, oneof, suchThat)
import Test.QuickCheck.Instances ()
+
-- | Healthy close transaction for the generic case were we close a head
+
-- after one or more snapshot have been agreed upon between the members.
healthyCloseTx :: (Tx, UTxO)
somePartyCardanoVerificationKey
+
healthyCloseLowerBoundSlot
+
healthyCloseUpperBoundPointInTime
(mkHeadId Fixture.testPolicyId)
-
-- here we need to pass in contestation period when generating start/end tx validity slots/time
-
-- since if tx validity bound difference is bigger than contestation period our close validator
-
(startSlot, pointInTime) =
-
genValidityBoundsFromContestationPeriod (fromChain healthyContestationPeriod) `generateWith` 42
+
lookupUTxO = UTxO.singleton (healthyOpenHeadTxIn, healthyOpenHeadTxOut)
+
headDatum = fromPlutusData $ toData healthyOpenHeadDatum
+
{ openThreadUTxO = (healthyOpenHeadTxIn, healthyOpenHeadTxOut, headDatum)
+
, openParties = healthyOnChainParties
+
, openContestationPeriod = healthyContestationPeriod
+
closingSnapshot :: ClosingSnapshot
+
CloseWithConfirmedSnapshot
+
{ snapshotNumber = healthySnapshotNumber
+
, closeUtxoHash = UTxOHash $ hashUTxO @Tx healthyCloseUTxO
+
, signatures = healthySignature healthySnapshotNumber
+
-- | Healthy close transaction for the specific case were we close a head
+
-- with the initial UtxO, that is, no snapshot have been agreed upon and
+
-- signed by the head members yet.
+
healthyCloseInitialTx :: (Tx, UTxO)
+
somePartyCardanoVerificationKey
+
healthyCloseLowerBoundSlot
+
healthyCloseUpperBoundPointInTime
+
(mkHeadId Fixture.testPolicyId)
lookupUTxO = UTxO.singleton (healthyOpenHeadTxIn, healthyOpenHeadTxOut)
-
headDatum = fromPlutusData $ toData healthyCloseDatum
+
headDatum = fromPlutusData $ toData healthyOpenHeadDatum
{ openThreadUTxO = (healthyOpenHeadTxIn, healthyOpenHeadTxOut, headDatum)
, openParties = healthyOnChainParties
, openContestationPeriod = healthyContestationPeriod
+
closingSnapshot :: ClosingSnapshot
+
CloseWithInitialSnapshot
+
{ openUtxoHash = UTxOHash $ hashUTxO @Tx healthyUTxO
+
-- NOTE: We need to use the contestation period when generating start/end tx
+
-- validity slots/time since if tx validity bound difference is bigger than
+
-- contestation period our close validator will fail
+
healthyCloseLowerBoundSlot :: SlotNo
+
healthyCloseUpperBoundPointInTime :: PointInTime
+
(healthyCloseLowerBoundSlot, healthyCloseUpperBoundPointInTime) =
+
genValidityBoundsFromContestationPeriod (fromChain healthyContestationPeriod) `generateWith` 42
healthyOpenHeadTxIn :: TxIn
healthyOpenHeadTxIn = generateWith arbitrary 42
mkHeadOutput testNetworkId Fixture.testPolicyId headTxOutDatum
& addParticipationTokens healthyParties
-
headTxOutDatum = toUTxOContext (mkTxOutDatum healthyCloseDatum)
-
healthySlotNo = arbitrary `generateWith` 42
-
healthyClosingSnapshot :: ClosingSnapshot
-
healthyClosingSnapshot =
-
CloseWithConfirmedSnapshot
-
{ snapshotNumber = healthySnapshotNumber
-
, closeUtxoHash = UTxOHash $ hashUTxO @Tx healthyCloseUTxO
-
, signatures = healthySignature healthySnapshotNumber
+
headTxOutDatum = toUTxOContext (mkTxOutDatum healthyOpenHeadDatum)
healthySnapshot :: Snapshot Tx
healthySnapshotNumber :: SnapshotNumber
healthySnapshotNumber = 1
-
healthyCloseDatum :: Head.State
+
healthyOpenHeadDatum :: Head.State
{ parties = healthyOnChainParties
, utxoHash = toBuiltin $ hashUTxO @Tx healthyUTxO
snapshot = healthySnapshot{number}
+
healthyContestationDeadline :: UTCTime
+
healthyContestationDeadline =
+
(fromInteger healthyContestationPeriodSeconds)
+
(snd healthyCloseUpperBoundPointInTime)
+
healthyClosedUTxOHash :: BuiltinByteString
+
toBuiltin $ hashUTxO @Tx healthyClosedUTxO
+
healthyClosedUTxO :: UTxO
+
genOneUTxOFor somePartyCardanoVerificationKey `generateWith` 42
= MutateSignatureButNotSnapshotNumber
-
| MutateSnapshotNumberButNotSignature
-
| MutateSnapshotToIllFormedValue
+
| -- | Change the resulting snapshot number, this should make the signature
+
MutateSnapshotNumberButNotSignature
+
| -- | This test the case when we have a non-initial utxo hash but the snapshot number is less than or equal to 0
+
MutateSnapshotNumberToLessThanZero
-
| MutateValidityInterval
-
| MutateCloseContestationDeadline
-
| MutateCloseContestationDeadlineWithZero
+
| MutatePartiesInOutput
+
| -- | See spec: 5.5 rule 4 -> contestationDeadline = upperBound + contestationPeriod
+
MutateContestationDeadline
+
| -- | See spec: 5.5. rule 5 -> upperBound - lowerBound <= contestationPeriod
deriving (Generic, Show, Enum, Bounded)
genCloseMutation :: (Tx, UTxO) -> Gen SomeMutation
genCloseMutation (tx, _utxo) =
-
-- FIXME: using 'closeRedeemer' here is actually too high-level and reduces
-
-- the power of the mutators, we should test at the level of the validator.
-
-- That is, using the on-chain types. 'closeRedeemer' is also not used
-
-- anywhere after changing this and can be moved into the closeTx
-
[ SomeMutation Nothing MutateSignatureButNotSnapshotNumber . ChangeHeadRedeemer <$> do