2
2
{-# Language DataKinds #-}
3
3
{-# Language FlexibleInstances #-}
4
4
{-# Language GADTs #-}
5
- {-# Language GeneralizedNewtypeDeriving #-}
6
5
{-# Language MultiParamTypeClasses #-}
7
6
{-# Language RankNTypes #-}
8
7
{-# Language TypeApplications #-}
@@ -12,12 +11,10 @@ module Cardano.Benchmarking.FundSet
12
11
where
13
12
import Prelude
14
13
15
- import Data.IxSet.Typed as IxSet
16
- import Data.Proxy
17
-
18
- import Control.Applicative ((<|>) )
19
14
import Cardano.Api as Api
20
15
16
+ import Cardano.Benchmarking.Fifo as Fifo
17
+
21
18
-- Outputs that are available for spending.
22
19
-- When building a new TX they provide the TxIn parts.
23
20
@@ -26,50 +23,27 @@ data FundInEra era = FundInEra {
26
23
, _fundWitness :: Witness WitCtxTxIn era
27
24
, _fundVal :: ! (TxOutValue era )
28
25
, _fundSigningKey :: ! (Maybe (SigningKey PaymentKey ))
29
- , _fundVariant :: ! Variant
30
- , _fundValidity :: ! Validity
31
26
} deriving (Show )
32
27
33
- data Variant
34
- = PlainOldFund
35
- -- maybe better use the script itself instead of the filePath
36
- | PlutusScriptFund
37
- -- A collateralFund is just a regular (PlainOldFund) on the chain,
38
- -- but tagged in the wallet so that it is not selected for spending.
39
- | CollateralFund
40
- deriving (Show , Eq , Ord )
41
-
42
- data Validity
43
- = Confirmed
44
- | InFlight ! Target ! SeqNumber
45
- deriving (Show , Eq , Ord )
46
-
47
- newtype Target = Target String
48
- deriving (Show , Eq , Ord )
49
-
50
- newtype SeqNumber = SeqNumber Int
51
- deriving (Show , Eq , Ord , Enum )
52
-
53
28
newtype Fund = Fund { unFund :: InAnyCardanoEra FundInEra }
54
29
55
- getFundVariant :: Fund -> Variant
56
- getFundVariant (Fund (InAnyCardanoEra _ a)) = _fundVariant a
30
+ type FundSet = Fifo Fund
31
+
32
+ type FundSource m = m (Either String [Fund ])
33
+ type FundToStore m = Fund -> m ()
34
+ type FundToStoreList m = [Fund ] -> m ()
57
35
58
36
getFundTxIn :: Fund -> TxIn
59
37
getFundTxIn (Fund (InAnyCardanoEra _ a)) = _fundTxIn a
60
38
61
39
getFundKey :: Fund -> Maybe (SigningKey PaymentKey )
62
40
getFundKey (Fund (InAnyCardanoEra _ a)) = _fundSigningKey a
63
41
64
- getFundValidity :: Fund -> Validity
65
- getFundValidity (Fund (InAnyCardanoEra _ a)) = _fundValidity a
66
-
67
42
getFundLovelace :: Fund -> Lovelace
68
43
getFundLovelace (Fund (InAnyCardanoEra _ a)) = case _fundVal a of
69
44
TxOutAdaOnly _era l -> l
70
45
TxOutValue _era v -> selectLovelace v
71
46
72
-
73
47
-- This effectively rules out era-transitions for transactions !
74
48
-- This is not what we want !!
75
49
getFundWitness :: forall era . IsShelleyBasedEra era => Fund -> Witness WitCtxTxIn era
@@ -85,14 +59,6 @@ getFundWitness fund = case (cardanoEra @ era, fund) of
85
59
-- It should be possible to cast KeyWitnesses from one era to an other !
86
60
(_ , _) -> error " getFundWitness: era mismatch"
87
61
88
- data IsConfirmed = IsConfirmed | IsNotConfirmed
89
- deriving (Show , Eq , Ord )
90
-
91
- isConfirmed :: Fund -> IsConfirmed
92
- isConfirmed f = case getFundValidity f of
93
- Confirmed -> IsConfirmed
94
- InFlight _ _ -> IsNotConfirmed
95
-
96
62
instance Show Fund where
97
63
show (Fund (InAnyCardanoEra _ f)) = show f
98
64
@@ -105,32 +71,11 @@ instance Eq Fund where
105
71
instance Ord Fund where
106
72
compare a b = compare (getFundTxIn a) (getFundTxIn b)
107
73
108
- type FundIndices = '[ TxIn , IsConfirmed , Target , SeqNumber , Lovelace , Variant ]
109
- type FundSet = IxSet FundIndices Fund
110
-
111
- instance Indexable FundIndices Fund where
112
- indices = ixList
113
- (ixFun $ \ f -> [ getFundTxIn f ])
114
- (ixFun $ \ f -> [ isConfirmed f ])
115
- (ixFun $ \ f -> case getFundValidity f of
116
- Confirmed -> []
117
- InFlight t _ -> [t]
118
- )
119
- (ixFun $ \ f -> case getFundValidity f of
120
- Confirmed -> [SeqNumber (- 1 ) ] -- Confirmed Txs get SeqNumber -1
121
- InFlight _ n -> [ n ]
122
- )
123
- (ixFun $ \ f -> [ getFundLovelace f ])
124
- (ixFun $ \ f -> [ getFundVariant f ])
125
-
126
- emptyFunds :: FundSet
127
- emptyFunds = IxSet. empty
74
+ emptyFundSet :: FundSet
75
+ emptyFundSet = Fifo. emptyFifo
128
76
129
77
insertFund :: FundSet -> Fund -> FundSet
130
- insertFund s f = updateIx (getFundTxIn f) f s
131
-
132
- deleteFund :: FundSet -> Fund -> FundSet
133
- deleteFund s f = deleteIx (getFundTxIn f) s
78
+ insertFund = Fifo. insert
134
79
135
80
liftAnyEra :: ( forall era . IsCardanoEra era => f1 era -> f2 era ) -> InAnyCardanoEra f1 -> InAnyCardanoEra f2
136
81
liftAnyEra f x = case x of
@@ -141,126 +86,6 @@ liftAnyEra f x = case x of
141
86
InAnyCardanoEra AlonzoEra a -> InAnyCardanoEra AlonzoEra $ f a
142
87
InAnyCardanoEra BabbageEra a -> InAnyCardanoEra BabbageEra $ f a
143
88
144
- type FundSelector = FundSet -> Either String [Fund ]
145
- type FundSource = IO (Either String [Fund ])
146
- type FundToStore = [Fund ] -> IO ()
147
-
148
- -- Select Funds to cover a minimum value.
149
- -- TODO:
150
- -- This fails unless there is a single fund with the required value
151
- -- Extend this to really return a list of funds.
152
- selectMinValue :: Lovelace -> FundSet -> Either String [Fund ]
153
- selectMinValue minValue fs = case coins of
154
- [] -> Left $ " findSufficientCoin: no single coin with min value >= " ++ show minValue
155
- (c: _) -> Right [c]
156
- where coins = toAscList ( Proxy :: Proxy Lovelace ) (fs @= PlainOldFund @= IsConfirmed @>= minValue)
157
-
158
- selectCollateral :: FundSet -> Either String [Fund ]
159
- selectCollateral fs = case coins of
160
- [] -> Left " no matching none-Plutus fund found"
161
- (c: _) -> Right [c]
162
- where
163
- coins = toAscList ( Proxy :: Proxy Lovelace ) (fs @= CollateralFund @= IsConfirmed )
164
-
165
- data AllowRecycle
166
- = UseConfirmedOnly
167
- | ReuseSameTarget
168
- -- ReuseAny can cause none-deterministic runtime errors !
169
- -- The problematic case is the reuse of an UTxO/Tx that is not yet confirmed
170
- -- and still waits in the mempool of an other target-node.
171
- | ReuseAny
172
- | ConfirmedBeforeReuse -- useful for testing
173
- deriving (Eq , Ord , Enum , Show )
174
-
175
- -- There are many possible heuristics to implement the selectInputs function.
176
- -- TODO: Check that the complexity of selectInputs is good enough.
177
- selectInputs ::
178
- AllowRecycle
179
- -> Int
180
- -> Lovelace
181
- -> Variant
182
- -> Target
183
- -> FundSet
184
- -> Either String [Fund ]
185
- selectInputs allowRecycle count minTotalValue variant targetNode fs
186
- = case allowRecycle of
187
- UseConfirmedOnly -> selectConfirmed
188
- ReuseSameTarget -> reuseSameTarget <|> selectConfirmed
189
- ReuseAny -> reuseSameTarget <|> selectConfirmed <|> reuseAnyCoin
190
- ConfirmedBeforeReuse -> selectConfirmed <|> reuseSameTarget
191
- where
192
- selectConfirmed = selectConfirmedSmallValue <|> selectConfirmedBigValue
193
-
194
- isSufficientCoins coins = length coins == count && sum (map getFundLovelace coins) >= minTotalValue
195
-
196
- checkCoins :: String -> [Fund ] -> Either String [Fund ]
197
- checkCoins err coins
198
- = if isSufficientCoins coins then Right coins else Left err
199
-
200
- -- Share intermediate results for variantIxSet confirmedIxSet and targetIxSet
201
- -- TODO: it unclear if this helps on the complexity or it it is even harmful.
202
- variantIxSet = fs @= variant
203
- confirmedIxSet = variantIxSet @= IsConfirmed
204
- targetIxSet = variantIxSet @= targetNode
205
-
206
- confirmedBigValueList = toDescList (Proxy :: Proxy Lovelace ) confirmedIxSet
207
- sameTargetList = toAscList (Proxy :: Proxy SeqNumber ) targetIxSet
208
-
209
- selectConfirmedSmallValue
210
- = checkCoins
211
- " selectConfirmedSmall: not enough coins available"
212
- (take count $ toAscList (Proxy :: Proxy Lovelace ) confirmedIxSet)
213
-
214
- selectConfirmedBigValue
215
- = checkCoins
216
- " selectConfirmedSmall: not enough coins available"
217
- (take count confirmedBigValueList)
218
-
219
- -- reuseSameTargetStrict is problematic: It fails if the coins in the queues are too small. But it will never consume the small coins.
220
- -- therefore: (reuseSameTargetStrict <|> reuseSameTargetWithBackup)
221
- reuseSameTargetStrict
222
- = checkCoins
223
- " reuseSameTargetStrict: not enough coins available"
224
- (take count sameTargetList)
225
-
226
- -- reuseSameTargetWithBackup can collect some dust.
227
- -- reuseSameTargetWithBackup works fine if there is at least one sufficient confirmed UTxO available.
228
- reuseSameTargetWithBackup = checkCoins " reuseSameTargetWithBackup: not enough coins available" (backupCoin ++ targetCoins)
229
- where
230
- -- targetCoins and backupCoins must be disjoint.
231
- -- This is case because IsConfirmed \= InFlight target.
232
- backupCoin = take 1 $ toAscList (Proxy :: Proxy Lovelace ) (confirmedIxSet @> minTotalValue)
233
- targetCoins = take (count - 1 ) sameTargetList
234
-
235
- reuseSameTarget = reuseSameTargetStrict <|> reuseSameTargetWithBackup
236
-
237
- -- reuseAnyCoin is the last resort !
238
- reuseAnyCoin
239
- = checkCoins
240
- " reuseAnyTarget: not enough coins available"
241
- (take count $ confirmedBigValueList ++ inFlightCoins)
242
- where
243
- -- inFlightCoins and confirmedCoins are disjoint
244
- inFlightCoins = toAscList (Proxy :: Proxy SeqNumber ) (variantIxSet @= IsNotConfirmed )
245
-
246
- selectToBuffer ::
247
- Int
248
- -> Lovelace
249
- -> Maybe Variant
250
- -> FundSet
251
- -> Either String [Fund ]
252
- selectToBuffer count minValue variant fs
253
- = if length coins < count
254
- then Left $ concat
255
- [ " selectToBuffer: not enough coins found: count: " , show count
256
- , " minValue: " , show minValue
257
- , " variant: " , show variant
258
- ]
259
- else Right coins
260
- where
261
- coins = case variant of
262
- Just v -> take count $ toAscList ( Proxy :: Proxy Lovelace ) (fs @= v @= IsConfirmed @>= minValue)
263
- Nothing -> take count $ toAscList ( Proxy :: Proxy Lovelace ) (fs @= IsConfirmed @>= minValue)
264
89
-- Todo: check sufficient funds and minimumValuePerUtxo
265
90
inputsToOutputsWithFee :: Lovelace -> Int -> [Lovelace ] -> [Lovelace ]
266
91
inputsToOutputsWithFee fee count inputs = map (quantityToLovelace . Quantity ) outputs
0 commit comments