@@ -5,6 +5,7 @@ module Test.DirectChainSpec where
5
5
import Hydra.Prelude
6
6
import Test.Hydra.Prelude
7
7
8
+ import Cardano.Ledger.Api (bodyTxL , reqSignerHashesTxBodyL )
8
9
import CardanoClient (
9
10
QueryPoint (QueryTip ),
10
11
RunningNode (.. ),
@@ -17,17 +18,23 @@ import CardanoClient (
17
18
import CardanoNode (NodeLog , withCardanoNodeDevnet )
18
19
import Control.Concurrent.STM (newEmptyTMVarIO , takeTMVar )
19
20
import Control.Concurrent.STM.TMVar (putTMVar )
21
+ import Control.Lens ((<>~) )
22
+ import Data.Set qualified as Set
20
23
import Hydra.Cardano.Api (
21
24
ChainPoint (.. ),
22
25
CtxUTxO ,
23
26
Key (SigningKey ),
24
27
PaymentKey ,
25
28
TxOut ,
26
29
UTxO' ,
30
+ fromLedgerTx ,
27
31
lovelaceToValue ,
28
32
signTx ,
33
+ toLedgerKeyHash ,
34
+ toLedgerTx ,
29
35
txOutValue ,
30
36
unFile ,
37
+ verificationKeyHash ,
31
38
)
32
39
import Hydra.Chain (
33
40
Chain (Chain , draftCommitTx , postTx ),
@@ -79,7 +86,7 @@ import Hydra.Party (Party)
79
86
import Hydra.Snapshot (ConfirmedSnapshot (.. ), Snapshot (.. ))
80
87
import System.FilePath ((</>) )
81
88
import System.Process (proc , readCreateProcess )
82
- import Test.QuickCheck (generate )
89
+ import Test.QuickCheck (choose , generate )
83
90
84
91
spec :: Spec
85
92
spec = around (showLogsOnFailure " DirectChainSpec" ) $ do
@@ -240,6 +247,38 @@ spec = around (showLogsOnFailure "DirectChainSpec") $ do
240
247
externalCommit node aliceChain aliceExternalSk headId mempty
241
248
aliceChain `observesInTime` OnCommitTx headId alice mempty
242
249
250
+ it " can commit with multiple required signatures" $ \ tracer -> do
251
+ withTempDir " hydra-cluster" $ \ tmp -> do
252
+ withCardanoNodeDevnet (contramap FromNode tracer) tmp $ \ node@ RunningNode {nodeSocket} -> do
253
+ hydraScriptsTxId <- publishHydraScriptsAs node Faucet
254
+ -- Alice setup
255
+ (aliceCardanoVk, _) <- keysFor Alice
256
+ seedFromFaucet_ node aliceCardanoVk 100_000_000 (contramap FromFaucet tracer)
257
+ aliceChainConfig <- chainConfigFor Alice tmp nodeSocket hydraScriptsTxId [] cperiod
258
+ withDirectChainTest (contramap (FromDirectChain " alice" ) tracer) aliceChainConfig alice $
259
+ \ aliceChain@ DirectChainTest {postTx} -> do
260
+ -- Scenario
261
+ participants <- loadParticipants [Alice ]
262
+ let headParameters = HeadParameters cperiod [alice]
263
+ postTx $ InitTx {participants, headParameters}
264
+ headId <- fst <$> aliceChain `observesInTimeSatisfying` hasInitTxWith headParameters participants
265
+
266
+ (aliceExternalVk, aliceExternalSk) <- generate genKeyPair
267
+ newAliceUTxO <- seedFromFaucet node aliceExternalVk 3_000_000 (contramap FromFaucet tracer)
268
+
269
+ numberOfKeyWits <- generate $ choose (2 , 10 )
270
+ randomKeys <- generate $ replicateM numberOfKeyWits genKeyPair
271
+
272
+ let blueprintTx =
273
+ fromLedgerTx
274
+ ( toLedgerTx (txSpendingUTxO newAliceUTxO)
275
+ & bodyTxL . reqSignerHashesTxBodyL
276
+ <>~ Set. fromList (toLedgerKeyHash . verificationKeyHash . fst <$> randomKeys)
277
+ )
278
+
279
+ externalCommit' node aliceChain (aliceExternalSk : fmap snd randomKeys) headId newAliceUTxO blueprintTx
280
+ aliceChain `observesInTime` OnCommitTx headId alice newAliceUTxO
281
+
243
282
it " can open, close & fanout a Head" $ \ tracer -> do
244
283
withTempDir " hydra-cluster" $ \ tmp -> do
245
284
withCardanoNodeDevnet (contramap FromNode tracer) tmp $ \ node@ RunningNode {nodeSocket, networkId} -> do
@@ -527,10 +566,24 @@ externalCommit ::
527
566
IO ()
528
567
externalCommit node hydraClient externalSk headId utxoToCommit = do
529
568
let blueprintTx = txSpendingUTxO utxoToCommit
569
+ externalCommit' node hydraClient [externalSk] headId utxoToCommit blueprintTx
570
+
571
+ externalCommit' ::
572
+ RunningNode ->
573
+ DirectChainTest Tx IO ->
574
+ [SigningKey PaymentKey ] ->
575
+ HeadId ->
576
+ UTxO' (TxOut CtxUTxO ) ->
577
+ Tx ->
578
+ IO ()
579
+ externalCommit' node hydraClient externalSks headId utxoToCommit blueprintTx = do
530
580
commitTx <- draftCommitTx headId utxoToCommit blueprintTx
531
- let signedTx = signTx externalSk commitTx
581
+ let signedTx = everybodySigns commitTx externalSks
532
582
submitTx node signedTx
533
583
where
584
+ everybodySigns tx' [] = tx'
585
+ everybodySigns tx' (sk : sks) = everybodySigns (signTx sk tx') sks
586
+
534
587
DirectChainTest {draftCommitTx} = hydraClient
535
588
536
589
-- | Load key files for given 'Actor's (see keysFor) and directly convert them to 'OnChainId'.
0 commit comments