| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Convex.ThreatModel.Cardano.Api
Synopsis
- type Era = ConwayEra
- type LedgerEra = ShelleyLedgerEra Era
- type IsPlutusScriptInEra lang = (HasScriptLanguageInEra lang Era, IsPlutusScriptLanguage lang)
- addressOfTxOut :: TxOut ctx Era -> AddressAny
- valueOfTxOut :: TxOut ctx Era -> Value
- datumOfTxOut :: TxOut ctx Era -> TxOutDatum ctx Era
- txBodyContentOf :: Tx Era -> TxBodyContent ViewTx Era
- bodyContentInputs :: TxBodyContent ViewTx Era -> [TxIn]
- bodyContentReferenceInputs :: TxBodyContent ViewTx Era -> [TxIn]
- bodyContentOutputs :: TxBodyContent ViewTx Era -> [TxOut CtxTx Era]
- referenceScriptOfTxOut :: TxOut ctx Era -> ReferenceScript Era
- redeemerOfTxIn :: Tx Era -> TxIn -> Maybe ScriptData
- mintedPlutusPolicies :: Tx Era -> UTxO Era -> [(PolicyId, PolicyAssets, ScriptInAnyLang, ScriptData)]
- recomputeScriptData :: Maybe Word32 -> (Word32 -> Word32) -> TxBodyScriptData Era -> TxBodyScriptData Era
- emptyTxBodyScriptData :: TxBodyScriptData Era
- addScriptData :: Word32 -> Data (ShelleyLedgerEra Era) -> (Data (ShelleyLedgerEra Era), ExUnits) -> TxBodyScriptData Era -> TxBodyScriptData Era
- updateRedeemer :: Word32 -> (Data (ShelleyLedgerEra Era), ExUnits) -> TxBodyScriptData Era -> TxBodyScriptData Era
- addMintingRedeemer :: Word32 -> (Data (ShelleyLedgerEra Era), ExUnits) -> TxBodyScriptData Era -> TxBodyScriptData Era
- recomputeScriptDataForMint :: Maybe Word32 -> (Word32 -> Word32) -> TxBodyScriptData Era -> TxBodyScriptData Era
- addDatum :: Data (ShelleyLedgerEra Era) -> TxBodyScriptData Era -> TxBodyScriptData Era
- toMaryAssetName :: AssetName -> AssetName
- paymentCredentialToAddressAny :: PaymentCredential -> AddressAny
- scriptAddressAny :: ScriptHash -> AddressAny
- keyAddressAny :: Hash PaymentKey -> AddressAny
- isKeyAddressAny :: AddressAny -> Bool
- toCtxUTxODatum :: TxOutDatum CtxTx Era -> TxOutDatum CtxUTxO Era
- txOutDatum :: ScriptData -> TxOutDatum CtxTx Era
- toScriptData :: ToData a => a -> ScriptData
- dummyTxId :: TxId
- makeTxOut :: AddressAny -> Value -> TxOutDatum CtxTx Era -> ReferenceScript Era -> TxOut CtxUTxO Era
- txSigners :: Tx Era -> [Hash PaymentKey]
- mockWalletHashes :: [(Hash PaymentKey, Wallet)]
- detectSigningWallet :: Tx Era -> Either String Wallet
- txRequiredSigners :: Tx Era -> [Hash PaymentKey]
- txOutputs :: Tx Era -> [TxOut CtxTx Era]
- txRunsPlutusScript :: Tx Era -> Bool
- runningPlutusScriptHashes :: UTxO LedgerEra -> Tx Era -> Set ScriptHash
- scriptHashOfAddressAny :: AddressAny -> Maybe ScriptHash
- leqValue :: Value -> Value -> Bool
- projectAda :: Value -> Value
- data ValidityReport = ValidityReport {
- errors :: [String]
- validity :: TxValidity
- data TxValidity
- validateTx :: LedgerProtocolParameters Era -> Tx Era -> UTxO Era -> ValidityReport
- validateTxM :: MonadMockchain Era m => NodeParams Era -> MockChainState Era -> Tx Era -> UTxO Era -> m (ValidityReport, CoverageData)
- buildMockState :: MockChainState Era -> SlotNo -> UTxO Era -> MockChainState Era
- chainStateUTxO :: MockChainState Era -> UTxO Era
- chainStateLedgerUTxO :: MockChainState Era -> UTxO LedgerEra
- chainStatePParams :: MockChainState Era -> LedgerProtocolParameters Era
- rebalanceAndSign :: MonadMockchain Era m => MockChainState Era -> Wallet -> Tx Era -> Tx Era -> UTxO Era -> m (Either String (Tx Era))
- updateExecutionUnits :: LedgerProtocolParameters Era -> SystemStart -> EraHistory -> UTxO Era -> Tx Era -> Either String (Tx Era)
- updateTxRedeemersWithExUnits :: Map ScriptWitnessIndex ExecutionUnits -> Tx Era -> Tx Era
- updateScriptDataExUnits :: Map ScriptWitnessIndex ExecutionUnits -> TxBodyScriptData Era -> TxBodyScriptData Era
- recalculateScriptIntegrityHash :: UTxO Era -> LedgerProtocolParameters Era -> Tx Era -> Tx Era
- recalculateTotalCollateral :: LedgerProtocolParameters Era -> UTxO Era -> Tx Era -> Either String (Tx Era)
- getScriptLanguage :: AlonzoScript LedgerEra -> Maybe Language
- setTxFeeCoin :: Coin -> Tx Era -> Tx Era
- setTxOutputsList :: [TxOut CtxTx Era] -> Tx Era -> Tx Era
- mkSizedShelleyTxOut :: TxOut CtxTx Era -> Sized (TxOut LedgerEra)
- adjustChangeOutput :: LedgerProtocolParameters Era -> AddressInEra Era -> Value -> [TxOut CtxTx Era] -> Either String [TxOut CtxTx Era]
- adjustOriginalChangeOutput :: LedgerProtocolParameters Era -> AddressInEra Era -> [TxOut CtxTx Era] -> Value -> [TxOut CtxTx Era] -> Either String [TxOut CtxTx Era]
- replaceAt :: Int -> a -> [a] -> [a]
- convValidityInterval :: (TxValidityLowerBound era, TxValidityUpperBound era) -> ValidityInterval
- restrictUTxO :: Tx Era -> UTxO Era -> UTxO Era
- extractCoverageFromValidationError :: String -> CoverageData
- unescapeHaskellString :: String -> String
- extractCoverageAnnotations :: String -> [String]
Types
type LedgerEra = ShelleyLedgerEra Era Source #
type IsPlutusScriptInEra lang = (HasScriptLanguageInEra lang Era, IsPlutusScriptLanguage lang) Source #
TxOut accessors
addressOfTxOut :: TxOut ctx Era -> AddressAny Source #
datumOfTxOut :: TxOut ctx Era -> TxOutDatum ctx Era Source #
Get the datum from a transaction output.
txBodyContentOf :: Tx Era -> TxBodyContent ViewTx Era Source #
The transaction's body content. Rebuilding this deserialises every
output's datum and reference script, so a caller that needs more than one
projection of the same transaction should take the body content once and
use the bodyContent* accessors (see ThreatModelEnv,
which caches it per env).
bodyContentInputs :: TxBodyContent ViewTx Era -> [TxIn] Source #
bodyContentOutputs :: TxBodyContent ViewTx Era -> [TxOut CtxTx Era] Source #
referenceScriptOfTxOut :: TxOut ctx Era -> ReferenceScript Era Source #
Redeemer and script data
redeemerOfTxIn :: Tx Era -> TxIn -> Maybe ScriptData Source #
mintedPlutusPolicies :: Tx Era -> UTxO Era -> [(PolicyId, PolicyAssets, ScriptInAnyLang, ScriptData)] Source #
Plutus minting policies (with their minted/burned assets and the redeemer used) that the given transaction already exercises. Each policy's script is resolved either from the transaction's own witness set or, for reference-script mints, from a UTxO among the chain state passed in. Native-script policies, and policies whose script can't be resolved, are omitted.
recomputeScriptData :: Maybe Word32 -> (Word32 -> Word32) -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
Re-key the Spending redeemers after the set of spend inputs changed: optionally drop the redeemer of a removed input, then apply the index shift to the remaining ones. Redeemers of every other purpose are indexed against their own item sets, which this change does not touch, so they pass through unchanged - shifting them would leave e.g. a withdrawal's redeemer pointing at the wrong (or a missing) reward account, and the ledger would reject the transaction in phase 1 with MissingRedeemer/ExtraRedeemers.
addScriptData :: Word32 -> Data (ShelleyLedgerEra Era) -> (Data (ShelleyLedgerEra Era), ExUnits) -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
updateRedeemer :: Word32 -> (Data (ShelleyLedgerEra Era), ExUnits) -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
Update only the redeemer for a spending input (does not modify TxDats) Use this when the original UTxO has an inline datum to avoid adding orphaned datums
addMintingRedeemer :: Word32 -> (Data (ShelleyLedgerEra Era), ExUnits) -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
Add a minting redeemer to the script data (no datum needed for minting)
recomputeScriptDataForMint :: Maybe Word32 -> (Word32 -> Word32) -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
Re-key the Minting redeemers after the set of minted policies changed.
addDatum :: Data (ShelleyLedgerEra Era) -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
toMaryAssetName :: AssetName -> AssetName Source #
Convert cardano-api AssetName to ledger Mary.AssetName
Address utilities
scriptAddressAny :: ScriptHash -> AddressAny Source #
Construct a script address.
keyAddressAny :: Hash PaymentKey -> AddressAny Source #
Construct a public key address.
isKeyAddressAny :: AddressAny -> Bool Source #
Check if an address is a public key address — i.e. has no script payment credential. Byron addresses count as key addresses, as they have no script credentials at all.
Datum/Redeemer conversion
txOutDatum :: ScriptData -> TxOutDatum CtxTx Era Source #
Convert ScriptData to a Datum.
toScriptData :: ToData a => a -> ScriptData Source #
Convert a Haskell value to ScriptData for use as a
Redeemer or convert to a
Datum with txOutDatum.
Transaction utilities
makeTxOut :: AddressAny -> Value -> TxOutDatum CtxTx Era -> ReferenceScript Era -> TxOut CtxUTxO Era Source #
mockWalletHashes :: [(Hash PaymentKey, Wallet)] Source #
detectSigningWallet :: Tx Era -> Either String Wallet Source #
Detect which mock wallet signed a transaction by examining its witnesses. Returns an error message if no known mock wallet is found among the signers.
txRequiredSigners :: Tx Era -> [Hash PaymentKey] Source #
Get the required signers from the transaction body (not witnesses).
txRunsPlutusScript :: Tx Era -> Bool Source #
Does this transaction run at least one Plutus script? See needsCollateral.
| Does any Plutus script run in this transaction? runningPlutusScriptHashes
answers which ones, and is empty exactly when this is False.
runningPlutusScriptHashes :: UTxO LedgerEra -> Tx Era -> Set ScriptHash Source #
The hashes of the Plutus scripts that run in this transaction.
Built from the ledger's own notion of which scripts a transaction must
satisfy (getScriptsNeeded), so it covers every purpose - spending,
minting, rewarding, certifying, voting, proposing - and cannot drift from
the ledger rules the way a hand-rolled redeemer walk would.
Narrowed to scripts *provided* as Plutus: a native script runs no Plutus
code and cannot inspect outputs at all, so it never guards anything.
Reference scripts are included, since getScriptsProvided resolves them
from the UTxO set rather than the witness set.
Empty exactly when txRunsPlutusScript is False, which is checked first
both to short-circuit the UTxO walk and to keep that equivalence true by
construction - guardedScriptOutputs relies on it to
subsume requireScriptExecution.
scriptHashOfAddressAny :: AddressAny -> Maybe ScriptHash Source #
The payment credential's script hash, or Nothing for a key or Byron
address. See guardedScriptOutputs for what matching
this against runningPlutusScriptHashes does and does not establish.
Value utilities
projectAda :: Value -> Value Source #
Keep only the Ada part of a value.
Validation
data ValidityReport Source #
The result of validating a transaction. In case of failure, it includes a list of reasons.
Constructors
| ValidityReport | |
Fields
| |
Instances
| Show ValidityReport Source # | |
Defined in Convex.ThreatModel.Cardano.Api Methods showsPrec :: Int -> ValidityReport -> ShowS # show :: ValidityReport -> String # showList :: [ValidityReport] -> ShowS # | |
| Eq ValidityReport Source # | |
Defined in Convex.ThreatModel.Cardano.Api Methods (==) :: ValidityReport -> ValidityReport -> Bool # (/=) :: ValidityReport -> ValidityReport -> Bool # | |
| Ord ValidityReport Source # | |
Defined in Convex.ThreatModel.Cardano.Api Methods compare :: ValidityReport -> ValidityReport -> Ordering # (<) :: ValidityReport -> ValidityReport -> Bool # (<=) :: ValidityReport -> ValidityReport -> Bool # (>) :: ValidityReport -> ValidityReport -> Bool # (>=) :: ValidityReport -> ValidityReport -> Bool # max :: ValidityReport -> ValidityReport -> ValidityReport # min :: ValidityReport -> ValidityReport -> ValidityReport # | |
data TxValidity Source #
The outcome of validating a transaction, mirroring the ledger's two-phase validation: Phase 2 (script execution) only runs when Phase 1 (structural ledger rules) passes, so no other combinations exist.
Constructors
| Valid | Phase 1 and Phase 2 both passed |
| Phase1Invalid | Rejected by Phase 1 ledger rules; scripts were never executed |
| Phase2Invalid | Phase 1 passed, but a script rejected the transaction |
Instances
| Show TxValidity Source # | |
Defined in Convex.ThreatModel.Cardano.Api Methods showsPrec :: Int -> TxValidity -> ShowS # show :: TxValidity -> String # showList :: [TxValidity] -> ShowS # | |
| Eq TxValidity Source # | |
Defined in Convex.ThreatModel.Cardano.Api | |
| Ord TxValidity Source # | |
Defined in Convex.ThreatModel.Cardano.Api Methods compare :: TxValidity -> TxValidity -> Ordering # (<) :: TxValidity -> TxValidity -> Bool # (<=) :: TxValidity -> TxValidity -> Bool # (>) :: TxValidity -> TxValidity -> Bool # (>=) :: TxValidity -> TxValidity -> Bool # max :: TxValidity -> TxValidity -> TxValidity # min :: TxValidity -> TxValidity -> TxValidity # | |
validateTx :: LedgerProtocolParameters Era -> Tx Era -> UTxO Era -> ValidityReport Source #
Validate a transaction using Phase 2 (script execution) validation only.
This uses evaluateTransactionExecutionUnits to check if Plutus scripts would accept or reject the transaction. It does NOT validate Phase 1 ledger rules (fees, signatures, value preservation, etc.) because threat model modifications alter the transaction body, invalidating signatures and fee calculations.
The purpose of threat models is to test script logic, not transaction construction.
Arguments
| :: MonadMockchain Era m | |
| => NodeParams Era | |
| -> MockChainState Era | The state the original transaction validated against (see
|
| -> Tx Era | |
| -> UTxO Era | |
| -> m (ValidityReport, CoverageData) |
Validate a transaction with full Phase 1 + Phase 2 validation inside MockchainT.
This uses applyTransaction which performs complete ledger validation including:
- Fee adequacy
- Signature verification
- UTxO existence
- Value preservation
- Validity intervals
- Collateral requirements
- Script execution (Phase 2)
buildMockState :: MockChainState Era -> SlotNo -> UTxO Era -> MockChainState Era Source #
Build a MockChainState for validation: the given base state - typically the state the original transaction validated against, so its certificate state (stake registrations, deposits, DRep and pool state) is intact - with the slot and the UTxO set replaced, and the accumulated coverage data blanked. The base state carries the coverage of every honest transaction replayed to reach it; blanking it makes the coverage read back after applying a modified transaction exactly that transaction's own delta, instead of honest-run coverage with the attack's mixed in.
chainStateUTxO :: MockChainState Era -> UTxO Era Source #
The UTxO set of a chain state.
chainStateLedgerUTxO :: MockChainState Era -> UTxO LedgerEra Source #
The chain state's UTxO set in ledger form, which is how it is actually
stored. chainStateUTxO converts it to the api type; anything that only
feeds it back to a ledger function should take this instead and skip the
round trip.
chainStatePParams :: MockChainState Era -> LedgerProtocolParameters Era Source #
The protocol parameters a chain state validates with.
Rebalancing
Arguments
| :: MonadMockchain Era m | |
| => MockChainState Era | The state the original transaction validated against (see
|
| -> Wallet | |
| -> Tx Era | The original, unmodified transaction: its outputs identify which
wallet output is the change output (see |
| -> Tx Era | The modified transaction to rebalance |
| -> UTxO Era | |
| -> m (Either String (Tx Era)) |
Re-balance fees, recalculate execution units, and re-sign a modified transaction.
After applying TxModifier operations, the transaction body changes which: 1. Invalidates the original signatures (body hash changed) 2. May require different fees (outputs changed) 3. May have invalid execution units (for added scripts)
This function:
1. Recalculates execution units for all scripts
2. Calculates the new required fee
3. Adjusts the change output (the original transaction's change output,
located in the modified one by adjustOriginalChangeOutput) to compensate
4. Re-signs the transaction with the wallet's key
A Left means the modification cannot be realized as a well-formed
transaction on this particular input (e.g. "No change output found", or no
usable collateral input) - a limitation of this function, not a verdict on
the transaction. The threat-model runners all treat it as a skipped test
rather than an error.
The steps below have a load-bearing order: each one's comment explains what
it needs to see from the ones before it. In particular, everything that can
change the transaction's *size* has to be reflected in the shape the fee is
estimated from - topUpUnderfundedOutputs and ensureCollateralInputShape
run before it, and the change output's absorption of the residual is solved
*together with* the fee as a fixed point (settle below), because each
determines the other. Reordering or interleaving a new corrective step
would still compile - it would only show up as an intermittent
property-test failure (a wrong fee, or BabbageOutputTooSmallUTxO), so
check each step's comment before moving anything.
updateExecutionUnits :: LedgerProtocolParameters Era -> SystemStart -> EraHistory -> UTxO Era -> Tx Era -> Either String (Tx Era) Source #
Update execution units in a transaction by evaluating all scripts.
This computes the actual execution units required for each script and updates the redeemers in the transaction with those values. This is necessary because TxModifier operations like addPlutusScriptMint use ExecutionUnits 0 0 as placeholders.
A script that runs and *rejects* the transaction shows up here as
ScriptErrorEvaluationFailed; its redeemer keeps its previous execution
units and the rejection is reported by the Phase 2 validation later - the
very outcome shouldNotValidate attacks look for. Every other evaluation
error is structural (a missing input, datum, script, or cost model, a
redeemer pointing nowhere, an execution-units overflow): the transaction the
modifier built cannot be meaningfully executed at all, so it is returned as
a Left and the run is skipped as environmental. Silently keeping the
placeholder units instead would fail Phase 2 on budget and be miscounted as
the validator rejecting the attack - a false negative.
updateTxRedeemersWithExUnits :: Map ScriptWitnessIndex ExecutionUnits -> Tx Era -> Tx Era Source #
Update the execution units in a transaction's redeemers.
This function takes a map from ScriptWitnessIndex to ExecutionUnits and updates the corresponding redeemers in the transaction.
updateScriptDataExUnits :: Map ScriptWitnessIndex ExecutionUnits -> TxBodyScriptData Era -> TxBodyScriptData Era Source #
Update execution units in TxBodyScriptData based on ScriptWitnessIndex map.
recalculateScriptIntegrityHash :: UTxO Era -> LedgerProtocolParameters Era -> Tx Era -> Tx Era Source #
Recalculate and update the script integrity hash in a transaction.
The script integrity hash commits to: - The redeemers in the transaction - The datums in the witness set - The cost models for languages used (from protocol parameters)
After modifying a transaction (addingremoving inputs, changing redeemersdatums), this hash becomes stale and must be recalculated.
recalculateTotalCollateral :: LedgerProtocolParameters Era -> UTxO Era -> Tx Era -> Either String (Tx Era) Source #
Recalculate the total collateral and collateral return based on the new fee.
Total collateral = ceiling(fee * collateralPercentage / 100) Collateral return = collateral input value - total collateral
This is needed because cardano-ledger is strict about collateral matching the fee. When the fee increases (e.g., due to bloated datum), we need to: 1. Increase the total collateral field 2. Decrease the collateral return (to provide more collateral)
If the transaction runs a Plutus script (spending, minting, or otherwise) but
doesn't have any collateral inputs yet - e.g. a TxModifier introduced a new
Plutus script, such as a minting policy, into a transaction that previously
ran no scripts at all - a key-address input already present in the
transaction is reused as the collateral input. The candidates are tried in
the order collateralInputCandidates ranks them (richest first) and the
first one that yields a buildable collateral arrangement wins, so a small
input that happens to sort first in TxIn order cannot mask a sufficient
one further down. The same UTxO can appear
in both the regular input set and the collateral input set: on a successful
script run the collateral fields are simply ignored by the ledger, so this
"double duty" is safe and is what a real wallet without a dedicated
collateral reserve would do too.
Collateral inputs that carry native tokens are supported: the ledger's collateral balance (inputs minus return output) must be pure ADA, so the return output is given exactly the inputs' tokens along with the leftover lovelace.
Returns Left if no suitable collateral input is available, or if the chosen collateral inputs don't have enough value to cover the required collateral. The latter can happen when a TxModifier significantly increases the transaction size (and thus the fee) - the original collateral may no longer be sufficient. Also returns Left for token-carrying collateral whose leftover lovelace can't fund the token-returning return output the tokens require.
getScriptLanguage :: AlonzoScript LedgerEra -> Maybe Language Source #
Extract the Plutus language from a ledger script, if it's a Plutus script
setTxOutputsList :: [TxOut CtxTx Era] -> Tx Era -> Tx Era Source #
Set transaction outputs (helper that works at the Tx level)
Arguments
| :: LedgerProtocolParameters Era | |
| -> AddressInEra Era | Wallet address to find change output |
| -> Value | Value delta to apply to the change output |
| -> [TxOut CtxTx Era] | Transaction outputs |
| -> Either String [TxOut CtxTx Era] |
Adjust the last output going to wallet address by a value delta (see
adjustOutputAt).
Taking the last wallet output as the change output is only a heuristic. It
assumes the transaction was balanced with trailing change
(TrailingChange; with LeadingChange the change
output comes first), and it goes wrong as soon as a TxModifier appends an
output to the wallet itself, since addOutput puts it after the real change
output. rebalanceAndSign therefore uses adjustOriginalChangeOutput, which
only falls back to this when it can't identify the change output from the
original transaction.
adjustOriginalChangeOutput Source #
Arguments
| :: LedgerProtocolParameters Era | |
| -> AddressInEra Era | Wallet address to find change output |
| -> [TxOut CtxTx Era] | The original (unmodified) transaction's outputs |
| -> Value | Value delta to apply to the change output |
| -> [TxOut CtxTx Era] | Transaction outputs |
| -> Either String [TxOut CtxTx Era] |
Adjust the change output by a value delta, identifying it through the
original transaction: its change output is taken to be its last wallet
output (see adjustChangeOutput), and that output is then located in the
modified outputs, trying in order:
- the original change output, still unchanged (the modifier may have shifted it by removing an earlier output);
- whatever wallet output sits at the original change output's index (the
modifier rewrote the change output in place, e.g. with
changeValueOf); - the last wallet output left unchanged by the modifier (the change output itself was removed);
adjustChangeOutput's choice, the last wallet output.
Going straight to the last wallet output of the modified transaction goes
wrong whenever a TxModifier adds an output to the wallet itself. Double
satisfaction, for one, redirects a victim's output to the signer with
addOutput, which appends it after the real change output; that new output
typically sits at its minimum ADA, so charging the fee to it fails with
"Change output would fall below the minimum required ADA" even though the
real change output could easily cover it. Conversely, looking only for
unchanged wallet outputs goes wrong when the modifier rewrote the change
output in place (as token forgery does): the fee would then be charged to an
earlier wallet output, such as an exact payment the validator checks.
Validity interval
convValidityInterval :: (TxValidityLowerBound era, TxValidityUpperBound era) -> ValidityInterval Source #
UTxO utilities
restrictUTxO :: Tx Era -> UTxO Era -> UTxO Era Source #
Keep only UTxOs mentioned in the given transaction.
Coverage
extractCoverageFromValidationError :: String -> CoverageData Source #
Extract coverage data from a ValidationError string containing CovLoc annotations. Handles the format found in Phase2 script evaluation errors where coverage annotations appear as "CoverLocation (CovLoc {...})" or "CoverBool (CovLoc {...}) Bool"
unescapeHaskellString :: String -> String Source #
Unescape common Haskell string escapes (backslash-quote to quote, backslash-backslash to backslash)
extractCoverageAnnotations :: String -> [String] Source #
Extract all "CoverLocation (...)" and "CoverBool (...)" substrings from text. Uses bracket counting to properly match nested parentheses.