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

Deadline gets "pushed out" on each contest #716

Merged
merged 24 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ef81ded
Add contestationPeriod to Closed head state
v0d1ch Feb 8, 2023
30a007c
Add mutation spec check we push contestation deadline on output
ffakenz Feb 8, 2023
e50062f
Push deadline using contestation period during contest tx building
ffakenz Feb 8, 2023
3b4351e
Add healthy contestation period to fanout and contest mutations
ffakenz Feb 8, 2023
5cda2c4
Add minor comment to explain the mutation on contestationd deadline
ffakenz Feb 8, 2023
db9fc9a
Add mutation spec check we push contestation deadline on input datum
ffakenz Feb 8, 2023
05632ba
Add mutation spec check we push contestation period on input datum
ffakenz Feb 8, 2023
cc6cfa0
Update changelog
v0d1ch Feb 8, 2023
a23785d
Do not push contestation deadline if the signer is the last one missi…
ffakenz Feb 8, 2023
5f302ff
Add mutation spec to check deadline is not pushed away
ffakenz Feb 8, 2023
9df8280
minor comments
ffakenz Feb 8, 2023
4f883c4
Remove spec as it was not working as expected
ffakenz Feb 8, 2023
949ed7a
Add a mutation to exercise the path where deadline shoult NOT get pushed
v0d1ch Feb 9, 2023
6307f46
Fix compilation errors
v0d1ch Feb 9, 2023
b27d189
Reduce the number of fanout outputs to 39
v0d1ch Feb 9, 2023
b217d04
Do not change the deadline in the mutation
v0d1ch Feb 9, 2023
e7a3ba3
Rename and generate a healthy state mutation
v0d1ch Feb 10, 2023
06a1b51
Finalize and document related mutation
v0d1ch Feb 10, 2023
a5dc824
Minor rename over contestation deadline in output datum
ffakenz Feb 10, 2023
36b6479
Add mutation spec to check that the contestation period does not chan…
ffakenz Feb 10, 2023
2e48bb4
Update head validator to check that the contestation period does not …
ffakenz Feb 10, 2023
b6ee2a7
Move functions to from module level to local scope in where block
ffakenz Feb 10, 2023
b09742d
Reduce fanout outputs by one
v0d1ch Feb 13, 2023
baabff9
Exclude healthyContestationPeriod
v0d1ch Feb 13, 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ changes.
+ The v_head output must now be the first output of the transaction so that we can make the validator code simpler.
+ Introduce check in head validator to allow contest only once per party.
+ Check that value is preserved in v_head
+ Introduce a function `(===!)` for strict equality check between serialized `Value`.
+ Introduce a function `(===)` for strict equality check between serialized `Value`.
ffakenz marked this conversation as resolved.
Show resolved Hide resolved
+ Push contestation deadline on contest.

- **BREAKING** Change the way tx validity and contestation deadline is constructed for close transactions:
+ There is a new hydra-node flag `--contestation-period` expressed in seconds
Expand Down
4 changes: 2 additions & 2 deletions hydra-node/src/Hydra/Chain/Direct/State.hs
Original file line number Diff line number Diff line change
Expand Up @@ -433,14 +433,14 @@ contest ::
PointInTime ->
Tx
contest ctx st confirmedSnapshot pointInTime = do
contestTx ownVerificationKey sn sigs pointInTime closedThreadOutput headId
contestTx ownVerificationKey sn sigs pointInTime closedThreadOutput headId contestationPeriod
where
(sn, sigs) =
case confirmedSnapshot of
ConfirmedSnapshot{signatures} -> (getSnapshot confirmedSnapshot, signatures)
_ -> (getSnapshot confirmedSnapshot, mempty)

ChainContext{ownVerificationKey} = ctx
ChainContext{contestationPeriod, ownVerificationKey} = ctx

ClosedState
{ closedThreadOutput
Expand Down
14 changes: 12 additions & 2 deletions hydra-node/src/Hydra/Chain/Direct/Tx.hs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ closeTx vk closing startSlotNo (endSlotNo, utcTime) openThreadOutput headId =
, utxoHash = toBuiltin utxoHashBytes
, parties = openParties
, contestationDeadline
, contestationPeriod = openContestationPeriod
, headId = headIdToCurrencySymbol headId
, contesters = []
}
Expand Down Expand Up @@ -391,8 +392,9 @@ contestTx ::
-- | Everything needed to spend the Head state-machine output.
ClosedThreadOutput ->
HeadId ->
ContestationPeriod ->
Tx
contestTx vk Snapshot{number, utxo} sig (slotNo, _) ClosedThreadOutput{closedThreadUTxO = (headInput, headOutputBefore, ScriptDatumForTxIn -> headDatumBefore), closedParties, closedContestationDeadline, closedContesters} headId =
contestTx vk Snapshot{number, utxo} sig (slotNo, _) ClosedThreadOutput{closedThreadUTxO = (headInput, headOutputBefore, ScriptDatumForTxIn -> headDatumBefore), closedParties, closedContestationDeadline, closedContesters} headId contestationPeriod =
unsafeBuildTransaction $
emptyTxBody
& addInputs [(headInput, headWitness)]
Expand All @@ -414,13 +416,21 @@ contestTx vk Snapshot{number, utxo} sig (slotNo, _) ClosedThreadOutput{closedThr

contester = toPlutusKeyHash (verificationKeyHash vk)

onChainConstestationPeriod = toChain contestationPeriod

newContestationDeadline =
if length (contester : closedContesters) == length closedParties
then closedContestationDeadline
else addContestationPeriod closedContestationDeadline onChainConstestationPeriod

headDatumAfter =
mkTxOutDatum
Head.Closed
{ snapshotNumber = toInteger number
, utxoHash
, parties = closedParties
, contestationDeadline = closedContestationDeadline
, contestationDeadline = newContestationDeadline
, contestationPeriod = onChainConstestationPeriod
, headId = headIdToCurrencySymbol headId
, contesters = contester : closedContesters
}
Expand Down
52 changes: 45 additions & 7 deletions hydra-node/test/Hydra/Chain/Direct/Contract/Contest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import Hydra.Chain.Direct.Contract.Mutation (
addParticipationTokens,
changeHeadOutputDatum,
changeMintedTokens,
replaceContestationDeadline,
replaceContestationPeriod,
replaceContesters,
replaceParties,
replacePolicyIdWith,
Expand All @@ -25,10 +27,12 @@ import Hydra.Chain.Direct.Contract.Mutation (
)
import Hydra.Chain.Direct.Fixture (testNetworkId, testPolicyId)
import Hydra.Chain.Direct.Tx (ClosedThreadOutput (..), contestTx, mkHeadId, mkHeadOutput)
import Hydra.ContestationPeriod (ContestationPeriod, fromChain)
import qualified Hydra.Contract.HeadState as Head
import Hydra.Contract.HeadTokens (headPolicyId)
import Hydra.Crypto (HydraKey, MultiSignature, aggregate, sign, toPlutusSignatures)
import Hydra.Data.ContestationPeriod (posixFromUTCTime)
import qualified Hydra.Data.ContestationPeriod as OnChain
import qualified Hydra.Data.Party as OnChain
import Hydra.Ledger (hashUTxO)
import Hydra.Ledger.Cardano (genOneUTxOFor, genValue, genVerificationKey)
Expand All @@ -39,26 +43,29 @@ import Plutus.Orphans ()
import Plutus.V2.Ledger.Api (BuiltinByteString, toBuiltin, toData)
import qualified Plutus.V2.Ledger.Api as Plutus
import Test.Hydra.Fixture (aliceSk, bobSk, carolSk)
import Test.QuickCheck (elements, listOf, oneof, suchThat)
import Test.QuickCheck (elements, listOf, oneof, suchThat, vectorOf)
import Test.QuickCheck.Gen (choose)
import Test.QuickCheck.Instances ()

--
-- ContestTx
--

-- | Healthy contest tx where the contester is the first one to contest and
-- correctly pushing out the deadline by the contestation period.
healthyContestTx :: (Tx, UTxO)
healthyContestTx =
(tx, lookupUTxO)
where
tx =
contestTx
somePartyCardanoVerificationKey
healthyContesterVerificationKey
healthyContestSnapshot
(healthySignature healthyContestSnapshotNumber)
(healthySlotNo, slotNoToUTCTime healthySlotNo)
closedThreadOutput
(mkHeadId testPolicyId)
healthyContestationPeriod

headDatum = fromPlutusData $ toData healthyClosedState

Expand Down Expand Up @@ -96,7 +103,7 @@ healthyContestSnapshotNumber = 4

healthyContestUTxO :: UTxO
healthyContestUTxO =
(genOneUTxOFor somePartyCardanoVerificationKey `suchThat` (/= healthyClosedUTxO))
(genOneUTxOFor healthyContesterVerificationKey `suchThat` (/= healthyClosedUTxO))
`generateWith` 42

healthyContestUTxOHash :: BuiltinByteString
Expand All @@ -110,6 +117,7 @@ healthyClosedState =
, utxoHash = healthyClosedUTxOHash
, parties = healthyOnChainParties
, contestationDeadline = posixFromUTCTime healthyContestationDeadline
, contestationPeriod = healthyOnChainContestationPeriod
, headId = toPlutusCurrencySymbol testPolicyId
, contesters = []
}
Expand All @@ -123,6 +131,12 @@ healthyContestationDeadline =
(fromInteger healthyContestationPeriodSeconds)
(slotNoToUTCTime healthySlotNo)

healthyOnChainContestationPeriod :: OnChain.ContestationPeriod
healthyOnChainContestationPeriod = OnChain.contestationPeriodFromDiffTime $ fromInteger healthyContestationPeriodSeconds

healthyContestationPeriod :: ContestationPeriod
healthyContestationPeriod = fromChain healthyOnChainContestationPeriod

healthyContestationPeriodSeconds :: Integer
healthyContestationPeriodSeconds = 10

Expand All @@ -135,10 +149,10 @@ healthyClosedUTxOHash =

healthyClosedUTxO :: UTxO
healthyClosedUTxO =
genOneUTxOFor somePartyCardanoVerificationKey `generateWith` 42
genOneUTxOFor healthyContesterVerificationKey `generateWith` 42

somePartyCardanoVerificationKey :: VerificationKey PaymentKey
somePartyCardanoVerificationKey = flip generateWith 42 $ do
healthyContesterVerificationKey :: VerificationKey PaymentKey
healthyContesterVerificationKey = flip generateWith 42 $ do
genForParty genVerificationKey <$> elements healthyParties

healthySigningKeys :: [SigningKey HydraKey]
Expand Down Expand Up @@ -181,6 +195,15 @@ data ContestMutation
MutateContesters
| -- | See spec: 5.5. rule 6 -> value is preserved
MutateValueInOutput
| -- | Change the 'ContestationDeadline' in the 'Closed' output datum such that deadline is pushed away
NotUpdateDeadlineAlthoughItShould
| -- | Pushes the deadline although this is the last contest. Instead of
-- creating another healthy case and mutate that one, this mutation just
-- changes the starting situation so that everyone else already contested.
-- Remember the 'healthyContestTx' is already pushing out the deadline.
PushDeadlineAlthoughItShouldNot
ffakenz marked this conversation as resolved.
Show resolved Hide resolved
| -- | Change the contestation period to test parameters not changed in output.
MutateOutputContestationPeriod
deriving (Generic, Show, Enum, Bounded)

genContestMutation :: (Tx, UTxO) -> Gen SomeMutation
Expand Down Expand Up @@ -238,7 +261,7 @@ genContestMutation
, SomeMutation (Just "minting or burning is forbidden") MutateTokenMintingOrBurning
<$> (changeMintedTokens tx =<< genMintedOrBurnedValue)
, SomeMutation (Just "signer already contested") MutateInputContesters . ChangeInputHeadDatum <$> do
let contester = toPlutusKeyHash (verificationKeyHash somePartyCardanoVerificationKey)
let contester = toPlutusKeyHash (verificationKeyHash healthyContesterVerificationKey)
contesterAndSomeOthers = do
contesters <- listOf $ Plutus.PubKeyHash . toBuiltin <$> genHash
pure (contester : contesters)
Expand All @@ -256,6 +279,21 @@ genContestMutation
, SomeMutation (Just "head value is not preserved") MutateValueInOutput <$> do
newValue <- genValue
pure $ ChangeOutput 0 (headTxOut{txOutValue = newValue})
, SomeMutation (Just "must push deadline") NotUpdateDeadlineAlthoughItShould . ChangeOutput 0 <$> do
let deadline = posixFromUTCTime healthyContestationDeadline
-- Here we are replacing the contestationDeadline using the previous so we are not _pushing it_ further
pure $ headTxOut & changeHeadOutputDatum (replaceContestationDeadline deadline)
, SomeMutation (Just "must not push deadline") PushDeadlineAlthoughItShouldNot <$> do
alreadyContested <- vectorOf (length healthyParties - 1) $ Plutus.PubKeyHash . toBuiltin <$> genHash
let contester = toPlutusKeyHash $ verificationKeyHash healthyContesterVerificationKey
pure $
Changes
[ ChangeOutput 0 (headTxOut & changeHeadOutputDatum (replaceContesters (contester : alreadyContested)))
, ChangeInputHeadDatum (healthyClosedState & replaceContesters alreadyContested)
]
, SomeMutation (Just "changed parameters") MutateOutputContestationPeriod <$> do
randomCP <- arbitrary `suchThat` (/= healthyOnChainContestationPeriod)
pure $ ChangeOutput 0 (headTxOut & changeHeadOutputDatum (replaceContestationPeriod randomCP))
]
where
headTxOut = fromJust $ txOuts' tx !!? 0
Expand Down
6 changes: 6 additions & 0 deletions hydra-node/test/Hydra/Chain/Direct/Contract/FanOut.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Hydra.Chain.Direct.Tx (fanoutTx, mkHeadOutput)
import qualified Hydra.Contract.HeadState as Head
import Hydra.Contract.HeadTokens (mkHeadTokenScript)
import Hydra.Data.ContestationPeriod (posixFromUTCTime)
import qualified Hydra.Data.ContestationPeriod as OnChain
import Hydra.Ledger (IsTx (hashUTxO))
import Hydra.Ledger.Cardano (
adaOnly,
Expand Down Expand Up @@ -81,9 +82,14 @@ healthyFanoutDatum =
, utxoHash = toBuiltin $ hashUTxO @Tx healthyFanoutUTxO
, parties = partyToChain <$> arbitrary `generateWith` 42
, contestationDeadline = posixFromUTCTime healthyContestationDeadline
, contestationPeriod = healthyContestationPeriod
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could: even use an arbitrary contestation period.

, headId = toPlutusCurrencySymbol testPolicyId
, contesters = []
}
where
healthyContestationPeriodSeconds = 10

healthyContestationPeriod = OnChain.contestationPeriodFromDiffTime $ fromInteger healthyContestationPeriodSeconds

data FanoutMutation
= MutateAddUnexpectedOutput
Expand Down
33 changes: 27 additions & 6 deletions hydra-node/test/Hydra/Chain/Direct/Contract/Mutation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ import qualified Hydra.Chain.Direct.Fixture as Fixture
import Hydra.Chain.Direct.Tx (assetNameFromVerificationKey)
import qualified Hydra.Contract.Head as Head
import qualified Hydra.Contract.HeadState as Head
import Hydra.Data.ContestationPeriod
import qualified Hydra.Data.Party as Data (Party)
import Hydra.Ledger.Cardano (genKeyPair, genOutput, genVerificationKey, renderTxWithUTxO)
import Hydra.Ledger.Cardano.Evaluate (evaluateTx)
Expand Down Expand Up @@ -644,12 +645,13 @@ replacePolicyIdWith originalPolicyId otherPolicyId output =

replaceSnapshotNumber :: Head.SnapshotNumber -> Head.State -> Head.State
replaceSnapshotNumber snapshotNumber = \case
Head.Closed{parties, utxoHash, contestationDeadline, headId, contesters} ->
Head.Closed{parties, utxoHash, contestationDeadline, headId, contesters, contestationPeriod} ->
Head.Closed
{ Head.parties = parties
, Head.snapshotNumber = snapshotNumber
, Head.utxoHash = utxoHash
, Head.contestationDeadline = contestationDeadline
, Head.contestationPeriod = contestationPeriod
, Head.headId = headId
, Head.contesters = contesters
}
Expand All @@ -670,12 +672,13 @@ replaceParties parties = \case
, Head.utxoHash = utxoHash
, Head.headId = headId
}
Head.Closed{snapshotNumber, utxoHash, contestationDeadline, headId, contesters} ->
Head.Closed{snapshotNumber, utxoHash, contestationDeadline, headId, contesters, contestationPeriod} ->
Head.Closed
{ Head.parties = parties
, Head.snapshotNumber = snapshotNumber
, Head.utxoHash = utxoHash
, Head.contestationDeadline = contestationDeadline
, Head.contestationPeriod = contestationPeriod
, Head.headId = headId
, Head.contesters = contesters
}
Expand All @@ -690,25 +693,41 @@ replaceUtxoHash utxoHash = \case
, Head.utxoHash = utxoHash
, Head.headId = headId
}
Head.Closed{parties, snapshotNumber, contestationDeadline, headId, contesters} ->
Head.Closed{parties, snapshotNumber, contestationDeadline, headId, contesters, contestationPeriod} ->
Head.Closed
{ Head.parties = parties
, Head.snapshotNumber = snapshotNumber
, Head.utxoHash = utxoHash
, Head.contestationDeadline = contestationDeadline
, Head.contestationPeriod = contestationPeriod
, Head.headId = headId
, Head.contesters = contesters
}
otherState -> otherState

replaceContestationDeadline :: POSIXTime -> Head.State -> Head.State
replaceContestationDeadline contestationDeadline = \case
Head.Closed{snapshotNumber, utxoHash, parties, headId, contesters} ->
Head.Closed{snapshotNumber, utxoHash, parties, headId, contesters, contestationPeriod} ->
Head.Closed
{ snapshotNumber
, utxoHash
, parties
, contestationDeadline
, contestationPeriod
, headId
, contesters
}
otherState -> otherState

replaceContestationPeriod :: ContestationPeriod -> Head.State -> Head.State
replaceContestationPeriod contestationPeriod = \case
Head.Closed{snapshotNumber, utxoHash, parties, headId, contesters, contestationDeadline} ->
Head.Closed
{ snapshotNumber
, utxoHash
, parties
, contestationDeadline
, contestationPeriod
, headId
, contesters
}
Expand All @@ -729,25 +748,27 @@ replaceHeadId headId = \case
, Head.utxoHash = utxoHash
, Head.headId = headId
}
Head.Closed{snapshotNumber, utxoHash, contestationDeadline, parties, contesters} ->
Head.Closed{snapshotNumber, utxoHash, contestationDeadline, parties, contesters, contestationPeriod} ->
Head.Closed
{ Head.parties = parties
, Head.snapshotNumber = snapshotNumber
, Head.utxoHash = utxoHash
, Head.contestationDeadline = contestationDeadline
, Head.contestationPeriod = contestationPeriod
, Head.headId = headId
, Head.contesters = contesters
}
otherState -> otherState

replaceContesters :: [Plutus.PubKeyHash] -> Head.State -> Head.State
replaceContesters contesters = \case
Head.Closed{snapshotNumber, utxoHash, contestationDeadline, parties, headId} ->
Head.Closed{snapshotNumber, utxoHash, contestationDeadline, parties, headId, contestationPeriod} ->
Head.Closed
{ Head.parties = parties
, Head.snapshotNumber = snapshotNumber
, Head.utxoHash = utxoHash
, Head.contestationDeadline = contestationDeadline
, Head.contestationPeriod = contestationPeriod
, Head.headId = headId
, Head.contesters = contesters
}
Expand Down
2 changes: 1 addition & 1 deletion hydra-node/test/Hydra/Chain/Direct/StateSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ forAllFanout action =
in action utxo tx
& label ("Fanout size: " <> prettyLength (countAssets $ txOuts' tx))
where
maxSupported = 45
maxSupported = 38

countAssets = getSum . foldMap (Sum . valueSize . txOutValue)

Expand Down
Loading