Skip to content

Commit

Permalink
Merge pull request #1161 from input-output-hk/ensemble/1087/multisign…
Browse files Browse the repository at this point in the history
…-headid

Include HeadId into Snapshot signatures
  • Loading branch information
ch1bo authored Nov 15, 2023
2 parents 9962f34 + f98218c commit ac19103
Show file tree
Hide file tree
Showing 42 changed files with 29,835 additions and 35,815 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ changes.

## [0.14.0] - UNRELEASED

- **BREAKING** Sign the head identifier as part of snapshot signature
and verify it on-chain

- Removed false positive `PostTxOnChainFailed` error from API outputs when the
collect transaction of another `hydra-node` was "faster" than ours.

Expand Down
2 changes: 1 addition & 1 deletion hydra-chain-observer/src/Hydra/ChainObserver.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import Hydra.Cardano.Api (
getTxId,
)
import Hydra.Cardano.Api.Prelude (TxId)
import Hydra.Chain (HeadId (..))
import Hydra.Chain.CardanoClient (queryTip)
import Hydra.Chain.Direct.Tx (
AbortObservation (..),
Expand All @@ -43,6 +42,7 @@ import Hydra.Chain.Direct.Tx (
import Hydra.ChainObserver.Options (Options (..), hydraChainObserverOptions)
import Hydra.Contract (ScriptInfo)
import Hydra.Contract qualified as Contract
import Hydra.HeadId (HeadId (..))
import Hydra.Ledger.Cardano (adjustUTxO)
import Hydra.Logging (Tracer, Verbosity (..), traceWith, withTracer)
import Options.Applicative (execParser)
Expand Down
2 changes: 1 addition & 1 deletion hydra-cluster/src/Hydra/Cluster/Scenarios.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ import Hydra.Cardano.Api (
writeFileTextEnvelope,
)
import Hydra.Cardano.Api.Prelude (ReferenceScript (..), TxOut (..), TxOutDatum (..))
import Hydra.Chain (HeadId)
import Hydra.Chain.Direct.Tx (assetNameFromVerificationKey)
import Hydra.Cluster.Faucet (FaucetLog, createOutputAtAddress, seedFromFaucet, seedFromFaucet_)
import Hydra.Cluster.Faucet qualified as Faucet
import Hydra.Cluster.Fixture (Actor (..), actorName, alice, aliceSk, aliceVk, bob, bobSk, bobVk, carol, carolSk)
import Hydra.Cluster.Util (chainConfigFor, keysFor)
import Hydra.ContestationPeriod (ContestationPeriod (UnsafeContestationPeriod))
import Hydra.HeadId (HeadId)
import Hydra.Ledger (IsTx (balance))
import Hydra.Ledger.Cardano (genKeyPair)
import Hydra.Logging (Tracer, traceWith)
Expand Down
41 changes: 23 additions & 18 deletions hydra-cluster/test/Test/DirectChainSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import Hydra.Cluster.Fixture (
import Hydra.Cluster.Util (chainConfigFor, keysFor)
import Hydra.ContestationPeriod (ContestationPeriod)
import Hydra.Crypto (aggregate, sign)
import Hydra.HeadId (HeadId)
import Hydra.Ledger (IsTx (..))
import Hydra.Ledger.Cardano (Tx, genKeyPair)
import Hydra.Logging (Tracer, nullTracer, showLogsOnFailure)
Expand Down Expand Up @@ -99,8 +100,8 @@ spec = around showLogsOnFailure $ do
\bobChain@DirectChainTest{} -> do
-- Scenario
postTx $ InitTx $ HeadParameters cperiod [alice, bob, carol]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]
bobChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]
void $ bobChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]

postTx $ AbortTx mempty

Expand Down Expand Up @@ -131,8 +132,8 @@ spec = around showLogsOnFailure $ do
aliceUTxO <- seedFromFaucet node aliceExternalVk aliceCommitment (contramap FromFaucet tracer)

postTx $ InitTx $ HeadParameters cperiod [alice, bob, carol]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]
bobChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]
void $ bobChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, bob, carol]

externalCommit node aliceChain aliceExternalSk aliceUTxO

Expand Down Expand Up @@ -172,7 +173,7 @@ spec = around showLogsOnFailure $ do
\DirectChainTest{postTx = bobPostTx} -> do
-- Scenario
alicePostTx $ InitTx $ HeadParameters cperiod [alice, carol]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, carol]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice, carol]

bobPostTx (AbortTx mempty)
`shouldThrow` \case
Expand All @@ -194,7 +195,7 @@ spec = around showLogsOnFailure $ do

postTx $ InitTx $ HeadParameters cperiod [alice]

aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
-- deliberately use alice's key known to hydra-node to trigger the error
externalCommit node aliceChain aliceCardanoSk aliceUTxO
`shouldThrow` \case
Expand All @@ -220,7 +221,7 @@ spec = around showLogsOnFailure $ do
\aliceChain@DirectChainTest{postTx} -> do
-- Scenario
postTx $ InitTx $ HeadParameters cperiod [alice]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]

(_, aliceExternalSk) <- generate genKeyPair
externalCommit node aliceChain aliceExternalSk mempty
Expand All @@ -242,7 +243,7 @@ spec = around showLogsOnFailure $ do
someUTxO <- seedFromFaucet node aliceExternalVk 1_000_000 (contramap FromFaucet tracer)

postTx $ InitTx $ HeadParameters cperiod [alice]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
headId <- aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]

externalCommit node aliceChain aliceExternalSk someUTxO
aliceChain `observesInTime` OnCommitTx alice someUTxO
Expand All @@ -252,7 +253,8 @@ spec = around showLogsOnFailure $ do

let snapshot =
Snapshot
{ number = 1
{ headId
, number = 1
, utxo = someUTxO
, confirmed = []
}
Expand Down Expand Up @@ -301,15 +303,15 @@ spec = around showLogsOnFailure $ do
\aliceChain@DirectChainTest{postTx} -> do
tip <- queryTip networkId nodeSocket
postTx $ InitTx $ HeadParameters cperiod [alice]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
pure tip

let aliceChainConfig' = aliceChainConfig{startChainFrom = Just tip}
-- REVIEW: It's a bit weird now that we would use the original chain
-- state here. Does this test even make sense with persistence?
withDirectChainTest (contramap (FromDirectChain "alice") tracer) aliceChainConfig' aliceChainContext $
\aliceChain@DirectChainTest{} ->
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
void $ aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]

it "cannot restart head to an unknown point" $ \tracer -> do
withTempDir "direct-chain" $ \tmp -> do
Expand Down Expand Up @@ -365,7 +367,7 @@ spec = around showLogsOnFailure $ do
someUTxO <- seedFromFaucet node aliceExternalVk 1_000_000 (contramap FromFaucet tracer)

postTx $ InitTx $ HeadParameters cperiod [alice]
aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]
headId <- aliceChain `observesInTimeSatisfying` hasInitTxWith cperiod [alice]

externalCommit node aliceChain aliceExternalSk someUTxO
aliceChain `observesInTime` OnCommitTx alice someUTxO
Expand All @@ -375,7 +377,7 @@ spec = around showLogsOnFailure $ do
-- Head is open with someUTxO

-- Alice close with the initial snapshot U0
postTx $ CloseTx InitialSnapshot{initialUTxO = someUTxO}
postTx $ CloseTx InitialSnapshot{headId, initialUTxO = someUTxO}
waitMatch aliceChain $ \case
Observation{observedTx = OnCloseTx{snapshotNumber}}
| snapshotNumber == 0 -> Just ()
Expand All @@ -384,7 +386,8 @@ spec = around showLogsOnFailure $ do
-- Alice contests with some snapshot U1 -> successful
let snapshot1 =
Snapshot
{ number = 1
{ headId
, number = 1
, utxo = someUTxO
, confirmed = []
}
Expand All @@ -398,7 +401,8 @@ spec = around showLogsOnFailure $ do
-- Alice contests with some snapshot U2 -> expect fail
let snapshot2 =
Snapshot
{ number = 2
{ headId
, number = 2
, utxo = someUTxO
, confirmed = []
}
Expand Down Expand Up @@ -458,18 +462,19 @@ withDirectChainTest tracer config ctx action = do
Right tx -> pure tx
}

hasInitTxWith :: (HasCallStack, IsTx tx) => ContestationPeriod -> [Party] -> OnChainTx tx -> Expectation
hasInitTxWith :: (HasCallStack, IsTx tx) => ContestationPeriod -> [Party] -> OnChainTx tx -> IO HeadId
hasInitTxWith expectedContestationPeriod expectedParties = \case
OnInitTx{contestationPeriod, parties} -> do
OnInitTx{headId, contestationPeriod, parties} -> do
expectedContestationPeriod `shouldBe` contestationPeriod
expectedParties `shouldBe` parties
pure headId
tx -> failure ("Unexpected observation: " <> show tx)

observesInTime :: IsTx tx => DirectChainTest tx IO -> OnChainTx tx -> IO ()
observesInTime chain expected =
observesInTimeSatisfying chain (`shouldBe` expected)

observesInTimeSatisfying :: DirectChainTest tx IO -> (OnChainTx tx -> Expectation) -> IO ()
observesInTimeSatisfying :: DirectChainTest tx IO -> (OnChainTx tx -> IO a) -> IO a
observesInTimeSatisfying DirectChainTest{waitCallback} check =
failAfter 10 go
where
Expand Down
3 changes: 2 additions & 1 deletion hydra-cluster/test/Test/EndToEndSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,8 @@ initAndClose tmpDir tracer clusterIx hydraScriptsTxId node@RunningNode{nodeSocke

let expectedSnapshot =
object
[ "snapshotNumber" .= int expectedSnapshotNumber
[ "headId" .= headId
, "snapshotNumber" .= int expectedSnapshotNumber
, "utxo" .= newUTxO
, "confirmedTransactions" .= [txId tx]
]
Expand Down
12 changes: 8 additions & 4 deletions hydra-node/bench/tx-cost/TxCost.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{-# LANGUAGE DuplicateRecordFields #-}

module TxCost where

import Hydra.Prelude hiding (catch)
Expand All @@ -16,6 +18,8 @@ import Hydra.Cardano.Api (
import Hydra.Cardano.Api.TxOut (toPlutusTxOut)
import Hydra.Chain.Direct.State (
ChainContext (contestationPeriod),
ClosedState (..),
OpenState (..),
abort,
close,
collect,
Expand Down Expand Up @@ -156,9 +160,9 @@ computeContestCost = do
genContestTx numParties = do
ctx <- genHydraContextFor numParties
utxo <- arbitrary
(closedSnapshotNumber, _, stClosed) <- genStClosed ctx utxo
(closedSnapshotNumber, _, stClosed@ClosedState{headId}) <- genStClosed ctx utxo
cctx <- pickChainContext ctx
snapshot <- genConfirmedSnapshot (succ closedSnapshotNumber) utxo (ctxHydraSigningKeys ctx)
snapshot <- genConfirmedSnapshot headId (succ closedSnapshotNumber) utxo (ctxHydraSigningKeys ctx)
pointInTime <- genPointInTimeBefore (getContestationDeadline stClosed)
pure (contest cctx stClosed snapshot pointInTime, getKnownUTxO stClosed <> getKnownUTxO cctx)

Expand Down Expand Up @@ -209,8 +213,8 @@ computeFanOutCost = do
genFanoutTx numParties numOutputs = do
utxo <- genUTxOAdaOnlyOfSize numOutputs
ctx <- genHydraContextFor numParties
(_committed, stOpen) <- genStOpen ctx
snapshot <- genConfirmedSnapshot 1 utxo [] -- We do not validate the signatures
(_committed, stOpen@OpenState{headId}) <- genStOpen ctx
snapshot <- genConfirmedSnapshot headId 1 utxo [] -- We do not validate the signatures
cctx <- pickChainContext ctx
let cp = contestationPeriod cctx
(startSlot, closePoint) <- genValidityBoundsFromContestationPeriod cp
Expand Down
Loading

0 comments on commit ac19103

Please sign in to comment.