Skip to content

Commit 7005f4d

Browse files
authored
Merge pull request #718 from IntersectMBO/mgalazyn/fix/autobalancing-when-credential-deregistration
Fix transaction autobalancing when deregistering credential
2 parents 9c62c9c + 63651cd commit 7005f4d

File tree

5 files changed

+156
-75
lines changed

5 files changed

+156
-75
lines changed

cardano-api/internal/Cardano/Api/Fees.hs

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import Data.Set (Set)
9898
import qualified Data.Set as Set
9999
import Data.Text (Text)
100100
import GHC.Exts (IsList (..))
101+
import GHC.Stack
101102
import Lens.Micro ((.~), (^.))
102103

103104
-- | Type synonym for logs returned by the ledger's @evalTxExUnitsWithLogs@ function.
@@ -190,7 +191,8 @@ instance Error (TxFeeEstimationError era) where
190191
-- | Use when you do not have access to the UTxOs you intend to spend
191192
estimateBalancedTxBody
192193
:: forall era
193-
. MaryEraOnwards era
194+
. HasCallStack
195+
=> MaryEraOnwards era
194196
-> TxBodyContent BuildTx era
195197
-> L.PParams (ShelleyLedgerEra era)
196198
-> Set PoolId
@@ -273,9 +275,9 @@ estimateBalancedTxBody
273275
, negateValue (lovelaceToValue totalDeposits)
274276
]
275277

276-
let change = toLedgerValue w $ calculateChangeValue sbe availableUTxOValue txbodycontent1
278+
let partialChange = toLedgerValue w $ calculatePartialChangeValue sbe availableUTxOValue txbodycontent1
277279
maxLovelaceChange = L.Coin (2 ^ (64 :: Integer)) - 1
278-
changeWithMaxLovelace = change & A.adaAssetL sbe .~ maxLovelaceChange
280+
changeWithMaxLovelace = partialChange & A.adaAssetL sbe .~ maxLovelaceChange
279281
changeTxOut =
280282
forShelleyBasedEraInEon
281283
sbe
@@ -1002,6 +1004,7 @@ data FeeEstimationMode era
10021004
makeTransactionBodyAutoBalance
10031005
:: forall era
10041006
. ()
1007+
=> HasCallStack
10051008
=> ShelleyBasedEra era
10061009
-> SystemStart
10071010
-> LedgerEpochInfo
@@ -1016,7 +1019,7 @@ makeTransactionBodyAutoBalance
10161019
-- ^ Map of all deposits for drep credentials that are being
10171020
-- unregistered in this transaction
10181021
-> UTxO era
1019-
-- ^ Just the transaction inputs, not the entire 'UTxO'.
1022+
-- ^ Just the transaction inputs (including reference and collateral ones), not the entire 'UTxO'.
10201023
-> TxBodyContent BuildTx era
10211024
-> AddressInEra era
10221025
-- ^ Change address
@@ -1042,18 +1045,21 @@ makeTransactionBodyAutoBalance
10421045
-- 3. update tx with fees
10431046
-- 4. balance the transaction and update tx change output
10441047

1045-
let totalValueAtSpendableUTxO = fromLedgerValue sbe . calculateIncomingUTxOValue . Map.elems $ unUTxO utxo
1046-
change =
1047-
monoidForEraInEon (toCardanoEra sbe) $ \w ->
1048-
toLedgerValue w $ calculateChangeValue sbe totalValueAtSpendableUTxO txbodycontent
1048+
txbodyForChange <- first TxBodyError $ createTransactionBody sbe txbodycontent
1049+
let initialChangeTxOut =
1050+
evaluateTransactionBalance sbe pp poolids stakeDelegDeposits drepDelegDeposits utxo txbodyForChange
10491051

1050-
txbody0 <-
1052+
-- Tx body used only for evaluating execution units. Because txout exact
1053+
-- values do not matter much here, we are using an initial change value,
1054+
-- which is slightly overestimated, because it does not include fee or
1055+
-- scripts execution costs.
1056+
txbody <-
10511057
first TxBodyError
10521058
$ createTransactionBody
10531059
sbe
10541060
$ txbodycontent
10551061
& modTxOuts
1056-
(<> [TxOut changeaddr (TxOutValueShelleyBased sbe change) TxOutDatumNone ReferenceScriptNone])
1062+
(<> [TxOut changeaddr initialChangeTxOut TxOutDatumNone ReferenceScriptNone])
10571063
exUnitsMapWithLogs <-
10581064
first TxBodyErrorValidityInterval $
10591065
evaluateTransactionExecutionUnits
@@ -1062,7 +1068,7 @@ makeTransactionBodyAutoBalance
10621068
history
10631069
lpp
10641070
utxo
1065-
txbody0
1071+
txbody
10661072

10671073
let exUnitsMap = Map.map (fmap snd) exUnitsMapWithLogs
10681074

@@ -1077,24 +1083,14 @@ makeTransactionBodyAutoBalance
10771083
txbodycontent1 <- substituteExecutionUnits exUnitsMap' txbodycontent
10781084

10791085
-- Make a txbody that we will use for calculating the fees. For the purpose
1080-
-- of fees we just need to make a txbody of the right size in bytes. We do
1081-
-- not need the right values for the fee or change output. We use
1082-
-- "big enough" values for the change output and set so that the CBOR
1083-
-- encoding size of the tx will be big enough to cover the size of the final
1084-
-- output and fee. Yes this means this current code will only work for
1085-
-- final fee of less than around 4000 ada (2^32-1 lovelace) and change output
1086-
-- of less than around 18 trillion ada (2^64-1 lovelace).
1087-
-- However, since at this point we know how much non-Ada change to give
1088-
-- we can use the true values for that.
1089-
let maxLovelaceChange = L.Coin (2 ^ (64 :: Integer)) - 1
1086+
-- of fees we just need to make a txbody of the right size in bytes. We
1087+
-- do not need the right values for the fee. We use "big enough" value
1088+
-- for the fee and set so that the CBOR encoding size of the tx will be
1089+
-- big enough to cover the size of the final output and fee. Yes this
1090+
-- means this current code will only work for final fee of less than
1091+
-- around 4000 ada (2^32-1 lovelace).
10901092
let maxLovelaceFee = L.Coin (2 ^ (32 :: Integer) - 1)
1091-
let changeWithMaxLovelace = change & A.adaAssetL sbe .~ maxLovelaceChange
1092-
let changeTxOut =
1093-
forShelleyBasedEraInEon
1094-
sbe
1095-
(lovelaceToTxOutValue sbe maxLovelaceChange)
1096-
(\w -> maryEraOnwardsConstraints w $ TxOutValueShelleyBased sbe changeWithMaxLovelace)
1097-
1093+
-- Make a txbody that we will use for calculating the fees.
10981094
let (dummyCollRet, dummyTotColl) = maybeDummyTotalCollAndCollReturnOutput sbe txbodycontent changeaddr
10991095
txbody1 <-
11001096
first TxBodyError $ -- TODO: impossible to fail now
@@ -1104,7 +1100,7 @@ makeTransactionBodyAutoBalance
11041100
{ txFee = TxFeeExplicit sbe maxLovelaceFee
11051101
, txOuts =
11061102
txOuts txbodycontent
1107-
<> [TxOut changeaddr changeTxOut TxOutDatumNone ReferenceScriptNone]
1103+
<> [TxOut changeaddr initialChangeTxOut TxOutDatumNone ReferenceScriptNone]
11081104
, txReturnCollateral = dummyCollRet
11091105
, txTotalCollateral = dummyTotColl
11101106
}
@@ -1240,15 +1236,10 @@ isNotAda _ = True
12401236
onlyAda :: Value -> Bool
12411237
onlyAda = null . toList . filterValue isNotAda
12421238

1243-
calculateIncomingUTxOValue
1244-
:: Monoid (Ledger.Value (ShelleyLedgerEra era))
1245-
=> [TxOut ctx era]
1246-
-> Ledger.Value (ShelleyLedgerEra era)
1247-
calculateIncomingUTxOValue providedUtxoOuts =
1248-
mconcat [v | (TxOut _ (TxOutValueShelleyBased _ v) _ _) <- providedUtxoOuts]
1249-
1250-
-- Calculation taken from validateInsufficientCollateral: https://github.com/input-output-hk/cardano-ledger/blob/389b266d6226dedf3d2aec7af640b3ca4984c5ea/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxo.hs#L335
1251-
-- TODO: Bug Jared to expose a function from the ledger that returns total and return collateral.
1239+
-- Calculation taken from validateInsufficientCollateral:
1240+
-- https://github.com/input-output-hk/cardano-ledger/blob/389b266d6226dedf3d2aec7af640b3ca4984c5ea/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxo.hs#L335
1241+
-- TODO: Bug Jared to expose a function from the ledger that returns total and
1242+
-- return collateral.
12521243
calcReturnAndTotalCollateral
12531244
:: ()
12541245
=> Ledger.AlonzoEraPParams (ShelleyLedgerEra era)
@@ -1311,17 +1302,19 @@ calcReturnAndTotalCollateral w fee pp' TxInsCollateral{} txReturnCollateral txTo
13111302
, totalCollateral
13121303
)
13131304

1314-
calculateCreatedUTOValue
1315-
:: ShelleyBasedEra era -> TxBodyContent build era -> Value
1316-
calculateCreatedUTOValue sbe txbodycontent =
1317-
mconcat [fromLedgerValue sbe v | (TxOut _ (TxOutValueShelleyBased _ v) _ _) <- txOuts txbodycontent]
1318-
1319-
calculateChangeValue
1320-
:: ShelleyBasedEra era -> Value -> TxBodyContent build era -> Value
1321-
calculateChangeValue sbe incoming txbodycontent =
1322-
let outgoing = calculateCreatedUTOValue sbe txbodycontent
1305+
-- | Calculate the partial change - this does not include certificates' deposits
1306+
calculatePartialChangeValue
1307+
:: ShelleyBasedEra era
1308+
-> Value
1309+
-> TxBodyContent build era
1310+
-> Value
1311+
calculatePartialChangeValue sbe incoming txbodycontent = do
1312+
let outgoing = newUtxoValue
13231313
mintedValue = txMintValueToValue $ txMintValue txbodycontent
1324-
in mconcat [incoming, mintedValue, negateValue outgoing]
1314+
mconcat [incoming, mintedValue, negateValue outgoing]
1315+
where
1316+
newUtxoValue =
1317+
mconcat [fromLedgerValue sbe v | (TxOut _ (TxOutValueShelleyBased _ v) _ _) <- txOuts txbodycontent]
13251318

13261319
-- | This is used in the balance calculation in the event where
13271320
-- the user does not supply the UTxO(s) they intend to spend
@@ -1585,7 +1578,8 @@ traverseScriptWitnesses =
15851578
traverse (\(item, eRes) -> eRes >>= (\res -> Right (item, res)))
15861579

15871580
calculateMinimumUTxO
1588-
:: ShelleyBasedEra era
1581+
:: HasCallStack
1582+
=> ShelleyBasedEra era
15891583
-> TxOut CtxTx era
15901584
-> Ledger.PParams (ShelleyLedgerEra era)
15911585
-> L.Coin

cardano-api/internal/Cardano/Api/IPC.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ data LocalNodeConnectInfo
174174
, localNodeNetworkId :: NetworkId
175175
, localNodeSocketPath :: SocketPath
176176
}
177+
deriving Show
177178

178179
-- ----------------------------------------------------------------------------
179180
-- Actually connect to the node

cardano-api/internal/Cardano/Api/Tx/Body.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1916,6 +1916,7 @@ instance Error TxBodyError where
19161916

19171917
createTransactionBody
19181918
:: ()
1919+
=> HasCallStack
19191920
=> ShelleyBasedEra era
19201921
-> TxBodyContent BuildTx era
19211922
-> Either TxBodyError (TxBody era)
@@ -2661,7 +2662,8 @@ convTotalCollateral txTotalCollateral =
26612662

26622663
convTxOuts
26632664
:: forall ctx era ledgerera
2664-
. ShelleyLedgerEra era ~ ledgerera
2665+
. HasCallStack
2666+
=> ShelleyLedgerEra era ~ ledgerera
26652667
=> ShelleyBasedEra era
26662668
-> [TxOut ctx era]
26672669
-> Seq.StrictSeq (Ledger.TxOut ledgerera)
@@ -2844,6 +2846,7 @@ guardShelleyTxInsOverflow txIns = do
28442846
-- all eras
28452847
mkCommonTxBody
28462848
:: ()
2849+
=> HasCallStack
28472850
=> ShelleyBasedEra era
28482851
-> TxIns BuildTx era
28492852
-> [TxOut ctx era]

cardano-api/internal/Cardano/Api/Tx/Compatible.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import Data.Maybe.Strict
3737
import Data.Monoid
3838
import qualified Data.Sequence.Strict as Seq
3939
import GHC.Exts (IsList (..))
40+
import GHC.Stack
4041
import Lens.Micro hiding (ix)
4142

4243
data AnyProtocolUpdate era where
@@ -206,7 +207,8 @@ createCompatibleSignedTx sbe ins outs witnesses txFee' anyProtocolUpdate anyVote
206207
.~ shelleyBootstrapWitnesses
207208

208209
createCommonTxBody
209-
:: ShelleyBasedEra era
210+
:: HasCallStack
211+
=> ShelleyBasedEra era
210212
-> [TxIn]
211213
-> [TxOut ctx era]
212214
-> Lovelace

0 commit comments

Comments
 (0)