From 3c97d156f5e27fdf30a9e795740112a844bdc995 Mon Sep 17 00:00:00 2001 From: Alexey Kuleshevich Date: Wed, 12 Feb 2025 13:23:58 -0700 Subject: [PATCH] Change `ApplyBlock` validatioon interface --- eras/shelley/impl/CHANGELOG.md | 6 + .../shelley/impl/cardano-ledger-shelley.cabal | 2 +- .../Cardano/Ledger/Shelley/API/Validation.hs | 225 +++++++++--------- .../test-suite/bench/BenchValidation.hs | 31 ++- .../Cardano/Ledger/Shelley/Generator/Block.hs | 2 +- .../Ledger/Shelley/Rules/AdaPreservation.hs | 3 - .../Ledger/Shelley/Rules/ClassifyTraces.hs | 1 - .../Ledger/Shelley/Rules/IncrementalStake.hs | 2 +- .../Test/Cardano/Ledger/Shelley/Rules/Pool.hs | 3 - .../Cardano/Ledger/Shelley/Rules/TestChain.hs | 7 +- libs/small-steps/CHANGELOG.md | 4 +- libs/small-steps/small-steps.cabal | 2 +- .../src/Control/State/Transition/Extended.hs | 33 +++ 13 files changed, 174 insertions(+), 147 deletions(-) diff --git a/eras/shelley/impl/CHANGELOG.md b/eras/shelley/impl/CHANGELOG.md index 7a7facd4dfe..93cfb154c1d 100644 --- a/eras/shelley/impl/CHANGELOG.md +++ b/eras/shelley/impl/CHANGELOG.md @@ -2,6 +2,12 @@ ## 1.16.0.0 +* Remove redundant supercalss constraints for `ApplyBlock` +* Add `applyBlockEither`, `applyBlockEitherNoEvents`, `applyBlockNoValidaton`, `applyTickNoEvents`. +* Add `applyBlock` and `applyTick` to `ApplyBlock` type class. +* Remove `applyBlockOpts` (in favor of `applyBlockEither`), `reapplyBlock` (in favor of + `applyBlockNoValidation`) and `applyTickOpts` (in favor `applyTick`). +* Disable validation level for `applyTick` * Add `DecCBOR` instances for: * `ShelleyTxWits` * `ShelleyTxAuxData` diff --git a/eras/shelley/impl/cardano-ledger-shelley.cabal b/eras/shelley/impl/cardano-ledger-shelley.cabal index e0e173f8d30..6d47429916c 100644 --- a/eras/shelley/impl/cardano-ledger-shelley.cabal +++ b/eras/shelley/impl/cardano-ledger-shelley.cabal @@ -118,7 +118,7 @@ library nothunks, quiet, set-algebra >=1.0, - small-steps >=1.1, + small-steps >=1.1.1, text, time, transformers, diff --git a/eras/shelley/impl/src/Cardano/Ledger/Shelley/API/Validation.hs b/eras/shelley/impl/src/Cardano/Ledger/Shelley/API/Validation.hs index 93009109e6b..9dcf0eacb80 100644 --- a/eras/shelley/impl/src/Cardano/Ledger/Shelley/API/Validation.hs +++ b/eras/shelley/impl/src/Cardano/Ledger/Shelley/API/Validation.hs @@ -11,13 +11,16 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE UndecidableSuperClasses #-} -- | Interface to the block validation and chain extension logic in the Shelley -- API. module Cardano.Ledger.Shelley.API.Validation ( ApplyBlock (..), - applyBlock, - applyTick, + applyBlockEither, + applyBlockEitherNoEvents, + applyBlockNoValidaton, + applyTickNoEvents, TickTransitionError (..), BlockTransitionError (..), chainChecks, @@ -26,7 +29,6 @@ where import Cardano.Ledger.BHeaderView (BHeaderView) import Cardano.Ledger.BaseTypes (Globals (..), ShelleyBase, Version) -import Cardano.Ledger.Binary (EncCBORGroup) import Cardano.Ledger.Block (Block) import qualified Cardano.Ledger.Chain as STS import Cardano.Ledger.Core @@ -38,11 +40,10 @@ import Cardano.Ledger.Shelley.PParams () import Cardano.Ledger.Shelley.Rules () import qualified Cardano.Ledger.Shelley.Rules as STS import Cardano.Ledger.Slot (SlotNo) -import Control.Arrow (left, right) import Control.Monad.Except import Control.Monad.Trans.Reader (runReader) import Control.State.Transition.Extended -import Data.List.NonEmpty (NonEmpty) +import Data.List.NonEmpty (NonEmpty (..)) import GHC.Generics (Generic) import Lens.Micro ((^.)) import NoThunks.Class (NoThunks (..)) @@ -51,133 +52,135 @@ import NoThunks.Class (NoThunks (..)) Block validation API -------------------------------------------------------------------------------} -class - ( STS (EraRule "TICK" era) - , BaseM (EraRule "TICK" era) ~ ShelleyBase - , Environment (EraRule "TICK" era) ~ () - , State (EraRule "TICK" era) ~ NewEpochState era - , Signal (EraRule "TICK" era) ~ SlotNo - , STS (EraRule "BBODY" era) - , BaseM (EraRule "BBODY" era) ~ ShelleyBase - , Environment (EraRule "BBODY" era) ~ STS.BbodyEnv era - , State (EraRule "BBODY" era) ~ STS.ShelleyBbodyState era - , Signal (EraRule "BBODY" era) ~ Block BHeaderView era - , EncCBORGroup (TxSeq era) - , State (EraRule "LEDGERS" era) ~ LedgerState era - ) => - ApplyBlock era - where - -- | Apply the header level ledger transition. - -- - -- This handles checks and updates that happen on a slot tick, as well as a - -- few header level checks, such as size constraints. - applyTickOpts :: - ApplySTSOpts ep -> - Globals -> - NewEpochState era -> - SlotNo -> - EventReturnType ep (EraRule "TICK" era) (NewEpochState era) - applyTickOpts opts globals state hdr = - either err id - . flip runReader globals - . applySTSOptsEither @(EraRule "TICK" era) opts - $ TRC ((), state, hdr) - where - err :: Show a => a -> b - err msg = error $ "Panic! applyTick failed: " <> show msg - - -- | Apply the block level ledger transition. - applyBlockOpts :: - forall ep m. - (EventReturnTypeRep ep, MonadError (BlockTransitionError era) m) => - ApplySTSOpts ep -> +class (EraGov era, EraSegWits era) => ApplyBlock era where + -- | Run the `BBODY` rule with `globalAssertionPolicy`. This function always succeeds, but + -- whenever validation is turned on it is necessary to check for presence of predicate failures + -- before a call can be marked successful. Therefore it is recommended to call `applyBlockEither` + -- instead. + applyBlock :: + SingEP ep -> + ValidationPolicy -> Globals -> NewEpochState era -> Block BHeaderView era -> - m (EventReturnType ep (EraRule "BBODY" era) (NewEpochState era)) - default applyBlockOpts :: - forall ep m. - (EventReturnTypeRep ep, MonadError (BlockTransitionError era) m, EraGov era) => - ApplySTSOpts ep -> + (NewEpochState era, [PredicateFailure (EraRule "BBODY" era)], [Event (EraRule "BBODY" era)]) + default applyBlock :: + ( STS (EraRule "BBODY" era) + , BaseM (EraRule "BBODY" era) ~ ShelleyBase + , Environment (EraRule "BBODY" era) ~ STS.BbodyEnv era + , State (EraRule "BBODY" era) ~ STS.ShelleyBbodyState era + , Signal (EraRule "BBODY" era) ~ Block BHeaderView era + , State (EraRule "LEDGERS" era) ~ LedgerState era + ) => + SingEP ep -> + ValidationPolicy -> Globals -> NewEpochState era -> Block BHeaderView era -> - m (EventReturnType ep (EraRule "BBODY" era) (NewEpochState era)) - applyBlockOpts opts globals state blk = - liftEither - . left BlockTransitionError - . right - ( mapEventReturn @ep @(EraRule "BBODY" era) $ - updateNewEpochState state - ) - $ res + (NewEpochState era, [PredicateFailure (EraRule "BBODY" era)], [Event (EraRule "BBODY" era)]) + applyBlock eventsPolicy validationPolicy globals newEpochState block = + (updateNewEpochState newEpochState stsResultState, stsResultFailures, stsResultEvents) where - res = - flip runReader globals - . applySTSOptsEither @(EraRule "BBODY" era) - opts - $ TRC (mkBbodyEnv state, bbs, blk) - bbs = + opts = + ApplySTSOpts + { asoAssertions = globalAssertionPolicy + , asoValidation = validationPolicy + , asoEvents = eventsPolicy + } + STSResult {stsResultState, stsResultFailures, stsResultEvents} = + flip runReader globals $ + applySTSOptsResult @(EraRule "BBODY" era) opts $ + TRC (mkBbodyEnv newEpochState, bBodyState, block) + bBodyState = STS.BbodyState - (LedgerState.esLState $ LedgerState.nesEs state) - (LedgerState.nesBcur state) - - -- | Re-apply a ledger block to the same state it has been applied to before. - -- - -- This function does no validation of whether the block applies successfully; - -- the caller implicitly guarantees that they have previously called - -- 'applyBlockTransition' on the same block and that this was successful. - reapplyBlock :: + (LedgerState.esLState $ LedgerState.nesEs newEpochState) + (LedgerState.nesBcur newEpochState) + + -- | Run the `TICK` rule with `globalAssertionPolicy` and without any validation, since it can't + -- fail anyways. + applyTick :: + SingEP ep -> Globals -> NewEpochState era -> - Block BHeaderView era -> - NewEpochState era - default reapplyBlock :: - EraGov era => + SlotNo -> + (NewEpochState era, [Event (EraRule "TICK" era)]) + default applyTick :: + ( STS (EraRule "TICK" era) + , BaseM (EraRule "TICK" era) ~ ShelleyBase + , Environment (EraRule "TICK" era) ~ () + , State (EraRule "TICK" era) ~ NewEpochState era + , Signal (EraRule "TICK" era) ~ SlotNo + ) => + SingEP ep -> Globals -> NewEpochState era -> - Block BHeaderView era -> - NewEpochState era - reapplyBlock globals state blk = - updateNewEpochState state res + SlotNo -> + (NewEpochState era, [Event (EraRule "TICK" era)]) + applyTick eventsPolicy globals newEpochState slotNo = (stsResultState, stsResultEvents) where - res = - flip runReader globals . reapplySTS @(EraRule "BBODY" era) $ - TRC (mkBbodyEnv state, bbs, blk) - bbs = - STS.BbodyState - (LedgerState.esLState $ LedgerState.nesEs state) - (LedgerState.nesBcur state) + opts = + ApplySTSOpts + { asoAssertions = globalAssertionPolicy + , asoValidation = ValidateNone + , asoEvents = eventsPolicy + } + STSResult {stsResultState, stsResultEvents} = + flip runReader globals . applySTSOptsResult @(EraRule "TICK" era) opts $ + TRC ((), newEpochState, slotNo) -applyTick :: +-- | Same as `applyBlock`, except it produces a Left when there are failures present and `Right` +-- with result otherwise. +applyBlockEither :: ApplyBlock era => + SingEP ep -> + ValidationPolicy -> Globals -> NewEpochState era -> - SlotNo -> - NewEpochState era -applyTick = - applyTickOpts $ - ApplySTSOpts - { asoAssertions = globalAssertionPolicy - , asoValidation = ValidateAll - , asoEvents = EPDiscard - } + Block BHeaderView era -> + Either (BlockTransitionError era) (NewEpochState era, [Event (EraRule "BBODY" era)]) +applyBlockEither eventsPolicy validationPolicy globals newEpochState block = + case failure of + [] -> Right (newEpochStateResult, events) + f : fs -> Left $ BlockTransitionError $ f :| fs + where + (newEpochStateResult, failure, events) = + applyBlock eventsPolicy validationPolicy globals newEpochState block -applyBlock :: - ( ApplyBlock era - , MonadError (BlockTransitionError era) m - ) => +applyBlockEitherNoEvents :: + ApplyBlock era => + ValidationPolicy -> Globals -> NewEpochState era -> Block BHeaderView era -> - m (NewEpochState era) -applyBlock = - applyBlockOpts $ - ApplySTSOpts - { asoAssertions = globalAssertionPolicy - , asoValidation = ValidateAll - , asoEvents = EPDiscard - } + Either (BlockTransitionError era) (NewEpochState era) +applyBlockEitherNoEvents validationPolicy globals newEpochState block = + fst <$> applyBlockEither EPDiscard validationPolicy globals newEpochState block + +-- | Re-apply a ledger block to the same state it has been applied to before. +-- +-- This function does no validation of whether the block applies successfully; +-- the caller implicitly guarantees that they have previously called +-- 'applyBlockTransition' on the same block and that this was successful. +applyBlockNoValidaton :: + ApplyBlock era => + Globals -> + NewEpochState era -> + Block BHeaderView era -> + NewEpochState era +applyBlockNoValidaton globals newEpochState block = newEpochStateResult + where + (newEpochStateResult, _failure, _events) = + applyBlock EPDiscard ValidateNone globals newEpochState block + +-- | Same as `applyTick`, but do not retain any ledger events +applyTickNoEvents :: + ApplyBlock era => + Globals -> + NewEpochState era -> + SlotNo -> + NewEpochState era +applyTickNoEvents globals newEpochState slotNo = + fst $ applyTick EPDiscard globals newEpochState slotNo instance ApplyBlock ShelleyEra diff --git a/eras/shelley/test-suite/bench/BenchValidation.hs b/eras/shelley/test-suite/bench/BenchValidation.hs index 283de810849..7690a3ea55c 100644 --- a/eras/shelley/test-suite/bench/BenchValidation.hs +++ b/eras/shelley/test-suite/bench/BenchValidation.hs @@ -1,15 +1,10 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# OPTIONS_GHC -Wno-orphans #-} @@ -55,6 +50,7 @@ import Cardano.Protocol.TPraos.Rules.Tickn (TicknState (..)) import Cardano.Slotting.Slot (withOriginToMaybe) import Control.DeepSeq (NFData (rnf)) import Control.Monad.Except () +import Control.State.Transition import qualified Data.Map.Strict as Map import Data.Proxy import Test.Cardano.Ledger.Shelley.ConcreteCryptoTypes (MockCrypto) @@ -104,37 +100,38 @@ genValidateInput n = do pure (ValidateInput testGlobals (chainNes chainstate) block) benchValidate :: - forall era. - (API.ApplyBlock era, Era era) => + (API.ApplyBlock era, Show (PredicateFailure (EraRule "BBODY" era))) => ValidateInput era -> IO (NewEpochState era) benchValidate (ValidateInput globals state (Block bh txs)) = - case API.applyBlock @era globals state (UnsafeUnserialisedBlock (makeHeaderView bh) txs) of - Right x -> pure x - Left x -> error (show x) + let block = UnsafeUnserialisedBlock (makeHeaderView bh) txs + in case API.applyBlockEitherNoEvents ValidateAll globals state block of + Right x -> pure x + Left x -> error (show x) applyBlock :: forall era. - ( EraTxOut era - , API.ApplyBlock era + ( API.ApplyBlock era , NFData (StashedAVVMAddresses era) , GovState era ~ ShelleyGovState era , EraCertState era + , Show (PredicateFailure (EraRule "BBODY" era)) ) => ValidateInput era -> Int -> Int applyBlock (ValidateInput globals state (Block bh txs)) n = - case API.applyBlock @era globals state (UnsafeUnserialisedBlock (makeHeaderView bh) txs) of - Right x -> seq (rnf x) (n + 1) - Left x -> error (show x) + let block = UnsafeUnserialisedBlock (makeHeaderView bh) txs + in case API.applyBlockEitherNoEvents ValidateAll globals state block of + Right x -> seq (rnf x) (n + 1) + Left x -> error (show x) benchreValidate :: - (API.ApplyBlock era, Era era) => + API.ApplyBlock era => ValidateInput era -> NewEpochState era benchreValidate (ValidateInput globals state (Block bh txs)) = - API.reapplyBlock globals state (UnsafeUnserialisedBlock (makeHeaderView bh) txs) + API.applyBlockNoValidaton globals state (UnsafeUnserialisedBlock (makeHeaderView bh) txs) -- ============================================================== diff --git a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Generator/Block.hs b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Generator/Block.hs index d76dc6762ac..ba09a2911b3 100644 --- a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Generator/Block.hs +++ b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Generator/Block.hs @@ -303,7 +303,7 @@ tickChainState ChainDepState {csProtocol, csTickn} = tickChainDepState testGlobals lv isNewEpoch cds PrtclState ocertIssue evNonce candNonce = csProtocol - nes' = applyTick testGlobals chainNes slotNo + nes' = applyTickNoEvents testGlobals chainNes slotNo in ChainState { chainNes = nes' , chainOCertIssue = ocertIssue diff --git a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/AdaPreservation.hs b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/AdaPreservation.hs index 5cf5ba2a4e0..044203cfcad 100644 --- a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/AdaPreservation.hs +++ b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/AdaPreservation.hs @@ -387,7 +387,6 @@ potsSumIncreaseWithdrawalsPerTx SourceSignalTarget {source = chainSt, signal = b potsSumIncreaseByRewardsPerTx :: forall era ledger. ( ChainProperty era - , EraSegWits era , TestingLedger era ledger ) => SourceSignalTarget (CHAIN era) -> @@ -495,7 +494,6 @@ preserveBalanceRestricted :: forall era ledger. ( ChainProperty era , TestingLedger era ledger - , EraSegWits era ) => SourceSignalTarget (CHAIN era) -> Property @@ -553,7 +551,6 @@ preserveOutputsTx SourceSignalTarget {source = chainSt, signal = block} = canRestrictUTxO :: forall era ledger. ( ChainProperty era - , EraSegWits era , TestingLedger era ledger ) => SourceSignalTarget (CHAIN era) -> diff --git a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/ClassifyTraces.hs b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/ClassifyTraces.hs index 2187e5de38b..3bc66dd7b7b 100644 --- a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/ClassifyTraces.hs +++ b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/ClassifyTraces.hs @@ -124,7 +124,6 @@ relevantCasesAreCovered n = relevantCasesAreCoveredForTrace :: forall era. ( ChainProperty era - , EraSegWits era , ShelleyEraTxBody era ) => Trace (CHAIN era) -> diff --git a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/IncrementalStake.hs b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/IncrementalStake.hs index 69546f9191d..6cb88187675 100644 --- a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/IncrementalStake.hs +++ b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/IncrementalStake.hs @@ -94,7 +94,7 @@ incrStakeComputationTest = incrStakeComp :: forall era ledger. - (EraSegWits era, ChainProperty era, TestingLedger era ledger) => + (ChainProperty era, TestingLedger era ledger) => SourceSignalTarget (CHAIN era) -> Property incrStakeComp SourceSignalTarget {source = chainSt, signal = block} = diff --git a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/Pool.hs b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/Pool.hs index f50aa6e5687..ec48aff013f 100644 --- a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/Pool.hs +++ b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/Pool.hs @@ -88,7 +88,6 @@ tests = -- retirement. poolRetirement :: ( ChainProperty era - , EraSegWits era , ShelleyEraTxBody era ) => SourceSignalTarget (CHAIN era) -> @@ -106,7 +105,6 @@ poolRetirement SourceSignalTarget {source = chainSt, signal = block} = -- in the retiring map. poolRegistration :: ( ChainProperty era - , EraSegWits era , ShelleyEraTxBody era ) => SourceSignalTarget (CHAIN era) -> @@ -121,7 +119,6 @@ poolRegistration (SourceSignalTarget {source = chainSt, signal = block}) = -- POOL` transition. poolStateIsInternallyConsistent :: ( ChainProperty era - , EraSegWits era , ShelleyEraTxBody era ) => SourceSignalTarget (CHAIN era) -> diff --git a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/TestChain.hs b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/TestChain.hs index b73a3ae6ebd..7eb9f2b275d 100644 --- a/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/TestChain.hs +++ b/eras/shelley/test-suite/src/Test/Cardano/Ledger/Shelley/Rules/TestChain.hs @@ -141,7 +141,6 @@ shortChainTrace constants f = withMaxSuccess 100 $ forAllChainTrace @era 10 cons ledgerTraceFromBlock :: forall era ledger. ( ChainProperty era - , EraSegWits era , TestingLedger era ledger ) => ChainState era -> @@ -161,7 +160,6 @@ ledgerTraceFromBlock chainSt block = ledgerTraceFromBlockWithRestrictedUTxO :: forall era ledger. ( ChainProperty era - , EraSegWits era , TestingLedger era ledger ) => ChainState era -> @@ -185,7 +183,6 @@ poolTraceFromBlock :: forall era. ( ChainProperty era , ShelleyEraTxBody era - , EraSegWits era ) => ChainState era -> Block (BHeader MockCrypto) era -> @@ -210,7 +207,6 @@ delegTraceFromBlock :: forall era. ( ChainProperty era , ShelleyEraTxBody era - , EraSegWits era ) => ChainState era -> Block (BHeader MockCrypto) era -> @@ -244,8 +240,7 @@ delegTraceFromBlock chainSt block = -- transactions with the LEDGERS rule) ledgerTraceBase :: forall era. - ( EraSegWits era - , GetLedgerView era + ( GetLedgerView era , ApplyBlock era ) => ChainState era -> diff --git a/libs/small-steps/CHANGELOG.md b/libs/small-steps/CHANGELOG.md index 4f93e5e0865..3a14ea7520b 100644 --- a/libs/small-steps/CHANGELOG.md +++ b/libs/small-steps/CHANGELOG.md @@ -1,8 +1,8 @@ # Version history for `small-steps` -## 1.1.0.2 +## 1.1.1.0 -* +* Add `STSResult` and `applySTSOptsResult` ## 1.1.0.1 diff --git a/libs/small-steps/small-steps.cabal b/libs/small-steps/small-steps.cabal index 27754099677..3fcead4b136 100644 --- a/libs/small-steps/small-steps.cabal +++ b/libs/small-steps/small-steps.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: small-steps -version: 1.1.0.1 +version: 1.1.1.0 license: Apache-2.0 maintainer: operations@iohk.io author: IOHK diff --git a/libs/small-steps/src/Control/State/Transition/Extended.hs b/libs/small-steps/src/Control/State/Transition/Extended.hs index a65ef1612cc..e6df58d0047 100644 --- a/libs/small-steps/src/Control/State/Transition/Extended.hs +++ b/libs/small-steps/src/Control/State/Transition/Extended.hs @@ -68,7 +68,9 @@ module Control.State.Transition.Extended ( AssertionPolicy (..), ValidationPolicy (..), ApplySTSOpts (..), + STSResult (..), applySTSOpts, + applySTSOptsResult, applySTSOptsEither, applySTS, applySTSIndifferently, @@ -503,6 +505,37 @@ type RuleInterpreter ep = Rule s rtype (State s) -> m (EventReturnType ep s (State s, [PredicateFailure s])) +data STSResult s = STSResult + { stsResultState :: State s + , stsResultFailures :: [PredicateFailure s] + , stsResultEvents :: [Event s] + } + +applySTSOptsResult :: + forall s m rtype ep. + (STS s, RuleTypeRep rtype, m ~ BaseM s) => + ApplySTSOpts ep -> + RuleContext rtype s -> + m (STSResult s) +applySTSOptsResult opts ctx = + case asoEvents opts of + EPDiscard -> do + (stsState, stsFailure) <- applySTSOpts opts ctx + pure + STSResult + { stsResultState = stsState + , stsResultFailures = stsFailure + , stsResultEvents = [] + } + EPReturn -> do + ((stsState, stsFailure), stsEvents) <- applySTSOpts opts ctx + pure + STSResult + { stsResultState = stsState + , stsResultFailures = stsFailure + , stsResultEvents = stsEvents + } + -- | Apply an STS with options. Note that this returns both the final state and -- the list of predicate failures. applySTSOpts ::