@@ -5,42 +5,40 @@ module Hydra.Chain.ScriptRegistry where
5
5
import Hydra.Prelude
6
6
7
7
import Cardano.Api.UTxO qualified as UTxO
8
+ import Data.List ((!!) )
8
9
import Hydra.Cardano.Api (
9
- AddressInEra ,
10
+ Coin ,
11
+ Era ,
10
12
EraHistory ,
11
13
Key (.. ),
12
14
LedgerEra ,
13
15
NetworkId ,
14
16
PParams ,
15
17
PaymentKey ,
16
- PlutusScript ,
17
18
PoolId ,
18
- ShelleyWitnessSigningKey (WitnessPaymentKey ),
19
19
SigningKey ,
20
20
SocketPath ,
21
21
SystemStart ,
22
22
Tx ,
23
- TxBody ,
23
+ TxBodyErrorAutoBalance ,
24
24
TxId ,
25
25
TxIn (.. ),
26
26
TxIx (.. ),
27
27
UTxO ,
28
28
WitCtx (.. ),
29
29
examplePlutusScriptAlwaysFails ,
30
- getTxBody ,
31
- isKeyAddress ,
32
- makeShelleyKeyWitness ,
33
- makeSignedTransaction ,
34
30
mkScriptAddress ,
35
31
mkScriptRef ,
32
+ mkTxIn ,
36
33
mkTxOutAutoBalance ,
37
34
mkVkAddress ,
38
35
selectLovelace ,
39
- throwErrorAsException ,
40
- txOutAddress ,
36
+ toCtxUTxOTxOut ,
41
37
txOutValue ,
38
+ txOuts' ,
42
39
pattern TxOutDatumNone ,
43
40
)
41
+ import Hydra.Cardano.Api.Tx (signTx )
44
42
import Hydra.Chain.CardanoClient (
45
43
QueryPoint (.. ),
46
44
awaitTransaction ,
@@ -54,7 +52,6 @@ import Hydra.Chain.CardanoClient (
54
52
submitTransaction ,
55
53
)
56
54
import Hydra.Contract.Head qualified as Head
57
- import Hydra.Ledger.Cardano (adjustUTxO )
58
55
import Hydra.Plutus (commitValidatorScript , initialValidatorScript )
59
56
import Hydra.Tx (txId )
60
57
import Hydra.Tx.ScriptRegistry (ScriptRegistry (.. ), newScriptRegistry )
@@ -105,54 +102,56 @@ publishHydraScripts networkId socketPath sk = do
105
102
where
106
103
vk = getVerificationKey sk
107
104
105
+ -- | Exception raised when building the script publishing transactions.
106
+ data PublishScriptException
107
+ = FailedToBuildPublishingTx (TxBodyErrorAutoBalance Era )
108
+ | FailedToFindUTxOToCoverDeposit { totalDeposit :: Coin }
109
+ deriving (Show )
110
+ deriving anyclass (Exception )
111
+
112
+ -- | Builds a chain of script publishing transactions.
113
+ -- Throws: PublishScriptException
108
114
buildScriptPublishingTxs ::
115
+ MonadThrow m =>
109
116
PParams LedgerEra ->
110
117
SystemStart ->
111
118
NetworkId ->
112
119
EraHistory ->
113
120
Set PoolId ->
121
+ -- | Outputs that can be spent by signing key.
114
122
UTxO ->
123
+ -- | Key owning funds to pay deposit and fees.
115
124
SigningKey PaymentKey ->
116
- IO [Tx ]
117
- buildScriptPublishingTxs pparams systemStart networkId eraHistory stakePools startUTxO sk =
118
- flip evalStateT (startUTxO, [] ) $
119
- forM scripts $ \ script -> do
120
- (nextUTxO, _) <- get
121
- (tx, _, spentUTxO) <- liftIO $ buildScriptPublishingTx pparams systemStart networkId eraHistory stakePools changeAddress sk script nextUTxO
122
- modify' (\ (_, existingTxs) -> (pickKeyAddressUTxO $ adjustUTxO tx spentUTxO, tx : existingTxs))
123
- pure tx
125
+ m [Tx ]
126
+ buildScriptPublishingTxs pparams systemStart networkId eraHistory stakePools availableUTxO sk = do
127
+ startUTxO <- findUTxO
128
+ go startUTxO scriptOutputs
124
129
where
125
- pickKeyAddressUTxO utxo = maybe mempty UTxO. singleton $ UTxO. findBy (\ (_, txOut) -> isKeyAddress (txOutAddress txOut)) utxo
130
+ -- Find a suitable utxo that covers at least the total deposit
131
+ findUTxO =
132
+ case UTxO. find (\ o -> selectLovelace (txOutValue o) > totalDeposit) availableUTxO of
133
+ Nothing -> throwIO FailedToFindUTxOToCoverDeposit {totalDeposit}
134
+ Just (i, o) -> pure $ UTxO. singleton (i, o)
126
135
127
- scripts = [initialValidatorScript, commitValidatorScript, Head. validatorScript]
136
+ totalDeposit = sum $ selectLovelace . txOutValue <$> scriptOutputs
128
137
129
- vk = getVerificationKey sk
138
+ scriptOutputs =
139
+ mkScriptTxOut . mkScriptRef
140
+ <$> [initialValidatorScript, commitValidatorScript, Head. validatorScript]
130
141
131
- changeAddress = mkVkAddress networkId vk
142
+ -- Loop over all script outputs to create while re-spending the change output
143
+ go _ [] = pure []
144
+ go utxo (out : rest) = do
145
+ tx <- case buildTransactionWithPParams' pparams systemStart eraHistory stakePools changeAddress utxo [] [out] of
146
+ Left err -> throwIO $ FailedToBuildPublishingTx err
147
+ Right tx -> pure $ signTx sk tx
148
+
149
+ let changeOutput = txOuts' tx !! 1
150
+ utxo' = UTxO. singleton (mkTxIn tx 1 , toCtxUTxOTxOut changeOutput)
151
+ (tx : ) <$> go utxo' rest
152
+
153
+ changeAddress = mkVkAddress networkId (getVerificationKey sk)
132
154
133
- buildScriptPublishingTx ::
134
- PParams LedgerEra ->
135
- SystemStart ->
136
- NetworkId ->
137
- EraHistory ->
138
- Set PoolId ->
139
- AddressInEra ->
140
- SigningKey PaymentKey ->
141
- PlutusScript ->
142
- UTxO. UTxO ->
143
- IO (Tx , TxBody , UTxO. UTxO )
144
- buildScriptPublishingTx pparams systemStart networkId eraHistory stakePools changeAddress sk script utxo =
145
- let output = mkScriptTxOut <$> [mkScriptRef script]
146
- totalDeposit = sum (selectLovelace . txOutValue <$> output)
147
- utxoToSpend =
148
- maybe mempty UTxO. singleton $
149
- UTxO. find (\ o -> selectLovelace (txOutValue o) > totalDeposit) utxo
150
- in case buildTransactionWithPParams' pparams systemStart eraHistory stakePools changeAddress utxoToSpend [] output of
151
- Left e -> throwErrorAsException e
152
- Right rawTx -> do
153
- let body = getTxBody rawTx
154
- pure (makeSignedTransaction [makeShelleyKeyWitness body (WitnessPaymentKey sk)] body, body, utxoToSpend)
155
- where
156
155
mkScriptTxOut =
157
156
mkTxOutAutoBalance
158
157
pparams
0 commit comments