Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Collection functions and exported symbols to be able to run a 'quickcheck-state-machine' counterexample using the GHC repl.
To test a counterexample first fire up the repl, and enable the
FlexibleContexts
and TypeFamilies
extensions, and set multi-line input.
cabal new-repl test-storage import Test.Ouroboros.Storage.ChainDB.StateMachine.Utils.RunOnRepl :set -XFlexibleContexts -XTypeFamilies +m
The commands that are part of the counterexample are usually several lines long. Thus it is better to create a local definition for them:
cmds = (<PASTE THE COMMANDS OF THE COUNTEREXAMPLE HERE>)
Note the use of parentheses to prevent GHCi from ending the multiline input prematurely (the copied counterexample in this case).
Then, the model and system under tests can be tested for lockstep agreement by running:
quickCheckCmdsLockStep someLoE someClockSkew someChunkInfo counterexample
Where someClockSkew
and someChunkInfo
are the ones given by the
counterexample found by quickcheck-statemachine, and someLoE
is LoEEnabled
()
or LoEDisabled
.
Synopsis
- quickCheckCmdsLockStep ∷ LoE () → SmallChunkInfo → Commands (At Cmd TestBlock IO) (At Resp TestBlock IO) → IO ()
- pattern At ∷ Block SlotNo (HeaderHash blk) → Point blk
- pattern Command ∷ t1 blk1 (IterRef blk1 m1 Symbolic) (FollowerRef blk1 m1 Symbolic) → t2 blk2 (IterRef blk2 m2 Symbolic) (FollowerRef blk2 m2 Symbolic) → [Var] → Command (At t1 blk1 m1) (At t2 blk2 m2)
- newtype Commands (cmd ∷ (Type → Type) → Type) (resp ∷ (Type → Type) → Type) = Commands {
- unCommands ∷ [Command cmd resp]
- newtype Reference a (r ∷ Type → Type) = Reference (r a)
- data Symbolic a where
- newtype Var = Var Int
- data Cmd blk it flr
- = AddBlock blk
- | GetCurrentChain
- | GetLedgerDB
- | GetTipBlock
- | GetTipHeader
- | GetTipPoint
- | GetBlockComponent (RealPoint blk)
- | GetGCedBlockComponent (RealPoint blk)
- | GetMaxSlotNo
- | GetIsValid (RealPoint blk)
- | Stream (StreamFrom blk) (StreamTo blk)
- | UpdateLoE (AnchoredFragment blk)
- | IteratorNext it
- | IteratorNextGCed it
- | IteratorClose it
- | NewFollower ChainType
- | FollowerInstruction flr
- | FollowerForward flr [Point blk]
- | FollowerClose flr
- | Close
- | Reopen
- | PersistBlks
- | PersistBlksThenGC
- | UpdateLedgerSnapshots
- | WipeVolatileDB
- newtype Resp blk it flr = Resp {
- getResp ∷ Either (ChainDbError blk) (Success blk it flr)
- data Success blk it flr
- = Unit ()
- | Chain (AnchoredFragment (Header blk))
- | LedgerDB (LedgerDB (ExtLedgerState blk))
- | MbBlock (Maybe blk)
- | MbAllComponents (Maybe (AllComponents blk))
- | MbGCedAllComponents (MaybeGCedBlock (AllComponents blk))
- | MbHeader (Maybe (Header blk))
- | Point (Point blk)
- | IsValid IsValidResult
- | UnknownRange (UnknownRange blk)
- | Iter it
- | IterResult (IteratorResult blk (AllComponents blk))
- | IterResultGCed (IteratorResultGCed blk)
- | Flr flr
- | MbChainUpdate (Maybe (ChainUpdate blk (AllComponents blk)))
- | MbPoint (Maybe (Point blk))
- | MaxSlot MaxSlotNo
- runCmdsLockstep ∷ LoE () → SmallChunkInfo → Commands (At Cmd Blk IO) (At Resp Blk IO) → Property
- newtype ChainLength = ChainLength Int
- data EBB
- = EBB !EpochNo
- | RegularBlock
- data SmallChunkInfo = SmallChunkInfo ChunkInfo
- data TestBlock = TestBlock {}
- data TestBody = TestBody {}
- newtype TestBodyHash = TestBodyHash Int
- data TestHeader = TestHeader {}
- newtype TestHeaderHash = TestHeaderHash Int
- data Block slot hash = Block {
- blockPointSlot ∷ !slot
- blockPointHash ∷ !hash
- newtype BlockNo = BlockNo {}
- data ChainHash (b ∷ k)
- = GenesisHash
- | BlockHash !(HeaderHash b)
- data ChainType = TentativeChain
- data ChainUpdate (block ∷ k) a = RollBack (Point block)
- data ChunkInfo = UniformChunkSize !ChunkSize
- data ChunkSize = ChunkSize {}
- newtype EpochNo = EpochNo Word64
- newtype SlotNo = SlotNo {}
Running the counterexamples
quickCheckCmdsLockStep ∷ LoE () → SmallChunkInfo → Commands (At Cmd TestBlock IO) (At Resp TestBlock IO) → IO () Source #
Patterns needed to disambiguate the At
and Command
symbols printed
pattern Command ∷ t1 blk1 (IterRef blk1 m1 Symbolic) (FollowerRef blk1 m1 Symbolic) → t2 blk2 (IterRef blk2 m2 Symbolic) (FollowerRef blk2 m2 Symbolic) → [Var] → Command (At t1 blk1 m1) (At t2 blk2 m2) Source #
Re-exports needed for compiling a StateMachine
inside the repl.
quickcheck-state-machine re-exports
newtype Commands (cmd ∷ (Type → Type) → Type) (resp ∷ (Type → Type) → Type) Source #
Commands | |
|
newtype Reference a (r ∷ Type → Type) Source #
Reference (r a) |
Instances
Foldable (Reference a ∷ (Type → Type) → Type) | |
Functor (Reference a ∷ (Type → Type) → Type) | |
Traversable (Reference a ∷ (Type → Type) → Type) | |
Defined in Test.StateMachine.Types.References | |
Generic (Reference a r) | |
Typeable a ⇒ Read (Reference a Symbolic) | |
(Show1 r, Show a) ⇒ Show (Reference a r) | |
(Eq a, Eq1 r) ⇒ Eq (Reference a r) | |
(Ord a, Ord1 r) ⇒ Ord (Reference a r) | |
Defined in Test.StateMachine.Types.References | |
type Rep (Reference a r) | |
Defined in Test.StateMachine.Types.References type Rep (Reference a r) = D1 ('MetaData "Reference" "Test.StateMachine.Types.References" "quickcheck-state-machine-0.10.1-l-no-vendored-treediff-9c56f317a325dbbe37595d9004904f12ac69339378b0e81a114f568b2b0b66ef" 'True) (C1 ('MetaCons "Reference" 'PrefixI 'False) (S1 ('MetaSel ('Nothing ∷ Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (r a)))) |
Instances
Generic Var | |
Read Var | |
Show Var | |
Eq Var | |
Ord Var | |
type Rep Var | |
Defined in Test.StateMachine.Types.References type Rep Var = D1 ('MetaData "Var" "Test.StateMachine.Types.References" "quickcheck-state-machine-0.10.1-l-no-vendored-treediff-9c56f317a325dbbe37595d9004904f12ac69339378b0e81a114f568b2b0b66ef" 'True) (C1 ('MetaCons "Var" 'PrefixI 'False) (S1 ('MetaSel ('Nothing ∷ Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int))) |
ChainDB.StateMachine re-exports
Commands
AddBlock blk | Advance the current slot to the block's slot (unless smaller than the current slot), add the block and run chain selection. |
GetCurrentChain | |
GetLedgerDB | |
GetTipBlock | |
GetTipHeader | |
GetTipPoint | |
GetBlockComponent (RealPoint blk) | |
GetGCedBlockComponent (RealPoint blk) | Only for blocks that may have been garbage collected. |
GetMaxSlotNo | |
GetIsValid (RealPoint blk) | |
Stream (StreamFrom blk) (StreamTo blk) | |
UpdateLoE (AnchoredFragment blk) | Update the LoE fragment and run chain selection. |
IteratorNext it | |
IteratorNextGCed it | Only for blocks that may have been garbage collected. |
IteratorClose it | |
NewFollower ChainType | |
FollowerInstruction flr |
|
FollowerForward flr [Point blk] | |
FollowerClose flr | |
Close | |
Reopen | |
PersistBlks | Copy the blocks older than |
PersistBlksThenGC | Copy the blocks older than The garbage collection procedure of the Chain DB (our system under test)
removes the blocks from the volatile DB without caring about whether
the removed blocks were persisted. Therefore, this part of the Chain DB
logic assumes that copy to the immutable DB took place before
garbage collection. The model uses this assumption as well. As a result,
we cannot perform garbage collection in isolation, since this will break
the model's |
UpdateLedgerSnapshots | Write a new |
WipeVolatileDB |
Instances
newtype Resp blk it flr Source #
Responses are either successful termination or an error.
Resp | |
|
Instances
Bifoldable (Resp blk) Source # | |
Bifunctor (Resp blk) Source # | |
Bitraversable (Resp blk) Source # | |
Defined in Test.Ouroboros.Storage.ChainDB.StateMachine bitraverse ∷ Applicative f ⇒ (a → f c) → (b → f d) → Resp blk a b → f (Resp blk c d) # | |
Foldable (Resp blk it) Source # | |
Defined in Test.Ouroboros.Storage.ChainDB.StateMachine fold ∷ Monoid m ⇒ Resp blk it m → m # foldMap ∷ Monoid m ⇒ (a → m) → Resp blk it a → m # foldMap' ∷ Monoid m ⇒ (a → m) → Resp blk it a → m # foldr ∷ (a → b → b) → b → Resp blk it a → b # foldr' ∷ (a → b → b) → b → Resp blk it a → b # foldl ∷ (b → a → b) → b → Resp blk it a → b # foldl' ∷ (b → a → b) → b → Resp blk it a → b # foldr1 ∷ (a → a → a) → Resp blk it a → a # foldl1 ∷ (a → a → a) → Resp blk it a → a # toList ∷ Resp blk it a → [a] # length ∷ Resp blk it a → Int # elem ∷ Eq a ⇒ a → Resp blk it a → Bool # maximum ∷ Ord a ⇒ Resp blk it a → a # minimum ∷ Ord a ⇒ Resp blk it a → a # | |
Traversable (Resp blk it) Source # | |
Defined in Test.Ouroboros.Storage.ChainDB.StateMachine | |
Functor (Resp blk it) Source # | |
(TestConstraints blk, Show it, Show flr) ⇒ Show (Resp blk it flr) Source # | |
(TestConstraints blk, Eq it, Eq flr) ⇒ Eq (Resp blk it flr) Source # | |
(TestConstraints blk, Eq1 r) ⇒ Eq (At Resp blk m r) Source # | |
data Success blk it flr Source #
Return type for successful database operations.
Unit () | |
Chain (AnchoredFragment (Header blk)) | |
LedgerDB (LedgerDB (ExtLedgerState blk)) | |
MbBlock (Maybe blk) | |
MbAllComponents (Maybe (AllComponents blk)) | |
MbGCedAllComponents (MaybeGCedBlock (AllComponents blk)) | |
MbHeader (Maybe (Header blk)) | |
Point (Point blk) | |
IsValid IsValidResult | |
UnknownRange (UnknownRange blk) | |
Iter it | |
IterResult (IteratorResult blk (AllComponents blk)) | |
IterResultGCed (IteratorResultGCed blk) | |
Flr flr | |
MbChainUpdate (Maybe (ChainUpdate blk (AllComponents blk))) | |
MbPoint (Maybe (Point blk)) | |
MaxSlot MaxSlotNo |
Instances
Bifoldable (Success blk) Source # | |
Bifunctor (Success blk) Source # | |
Bitraversable (Success blk) Source # | |
Defined in Test.Ouroboros.Storage.ChainDB.StateMachine bitraverse ∷ Applicative f ⇒ (a → f c) → (b → f d) → Success blk a b → f (Success blk c d) # | |
Foldable (Success blk it) Source # | |
Defined in Test.Ouroboros.Storage.ChainDB.StateMachine fold ∷ Monoid m ⇒ Success blk it m → m # foldMap ∷ Monoid m ⇒ (a → m) → Success blk it a → m # foldMap' ∷ Monoid m ⇒ (a → m) → Success blk it a → m # foldr ∷ (a → b → b) → b → Success blk it a → b # foldr' ∷ (a → b → b) → b → Success blk it a → b # foldl ∷ (b → a → b) → b → Success blk it a → b # foldl' ∷ (b → a → b) → b → Success blk it a → b # foldr1 ∷ (a → a → a) → Success blk it a → a # foldl1 ∷ (a → a → a) → Success blk it a → a # toList ∷ Success blk it a → [a] # null ∷ Success blk it a → Bool # length ∷ Success blk it a → Int # elem ∷ Eq a ⇒ a → Success blk it a → Bool # maximum ∷ Ord a ⇒ Success blk it a → a # minimum ∷ Ord a ⇒ Success blk it a → a # | |
Traversable (Success blk it) Source # | |
Defined in Test.Ouroboros.Storage.ChainDB.StateMachine | |
Functor (Success blk it) Source # | |
(TestConstraints blk, Show it, Show flr) ⇒ Show (Success blk it flr) Source # | |
(TestConstraints blk, Eq it, Eq flr) ⇒ Eq (Success blk it flr) Source # | |
runCmdsLockstep ∷ LoE () → SmallChunkInfo → Commands (At Cmd Blk IO) (At Resp Blk IO) → Property Source #
Test packages re-exports
newtype ChainLength Source #
In chain selection, we use BlockNo
as a proxy for the block length.
This is entirely correct, except for those dreadful EBBs, which share their
block number with their predecessor. So it is possible that two chains with
the same BlockNo
at the tip have a different length because the longer
chain contains more EBBs than the shorter.
For example:
.. :> EBB (100, slotNo 10, blockNo 1) :> (400, slotNo 10, blockNo 2) .. :> (999, slotNo 10, blockNo 2)
The chain selection for this TestBlock
looks at the hashes in case of a
BlockNo
tie (after prefering the chain ending with an EBB) and will pick
the block with the highest hash. This is to have a more deterministic chain
selection (less implementation specific) which will keep the model better
in sync with the implementation.
In the example above, that would mean picking the second chain, /even though it is shorter/! The implementation does not support switching to a shorter chain.
Note that this is not a problem for Byron, because we don't look at the hashes or anything else in case of a tie (we just prefer a chain ending with an EBB, which must be longer).
Note that is not a problem for Shelley either, where we do look at the certificate number and VRF hash in case of a tie, because there are no EBBs.
This is only an issue when:
* There can be EBBs in the chain
* In case of equal blockNo
s, we still prefer one over the other because
of some additional condition.
Which is the case for this TestBlock.
To solve this, we store the real chain length inside the block. The only
difference with the BlockNo
is that ChainLength
takes EBBs into account.
When there is BlockNo
tie as in the example above and we would look at
the hashes, we will first look at the ChainLength
(and prefer the longest
one). Only if that is equal do we actually look at the hashes. This
guarantees that we never prefer a chain that is shorter.
NOTE: we start counting from 1 (unlike BlockNo
, which starts from 0),
because it corresponds to the length.
Instances
Strict variant of Maybe EpochNo
Instances
Generic EBB Source # | |
Show EBB Source # | |
Eq EBB Source # | |
Hashable EBB Source # | |
NoThunks EBB Source # | |
Serialise EBB Source # | |
ToExpr EBB Source # | |
type Rep EBB Source # | |
Defined in Test.Ouroboros.Storage.TestBlock type Rep EBB = D1 ('MetaData "EBB" "Test.Ouroboros.Storage.TestBlock" "ouroboros-consensus-0.21.0.0-inplace-storage-test" 'False) (C1 ('MetaCons "EBB" 'PrefixI 'False) (S1 ('MetaSel ('Nothing ∷ Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 EpochNo)) :+: C1 ('MetaCons "RegularBlock" 'PrefixI 'False) (U1 ∷ Type → Type)) |
data SmallChunkInfo Source #
Instances
Arbitrary SmallChunkInfo | |
Defined in Test.Util.ChunkInfo | |
Show SmallChunkInfo | |
Defined in Test.Util.ChunkInfo showsPrec ∷ Int → SmallChunkInfo → ShowS # show ∷ SmallChunkInfo → String # showList ∷ [SmallChunkInfo] → ShowS # |
Instances
TestBody | |
|
Instances
Generic TestBody Source # | |
Show TestBody Source # | |
Eq TestBody Source # | |
Hashable TestBody Source # | |
NoThunks TestBody Source # | |
Serialise TestBody Source # | |
ToExpr TestBody Source # | |
type Rep TestBody Source # | |
Defined in Test.Ouroboros.Storage.TestBlock type Rep TestBody = D1 ('MetaData "TestBody" "Test.Ouroboros.Storage.TestBlock" "ouroboros-consensus-0.21.0.0-inplace-storage-test" 'False) (C1 ('MetaCons "TestBody" 'PrefixI 'True) (S1 ('MetaSel ('Just "tbForkNo") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Word) :*: S1 ('MetaSel ('Just "tbIsValid") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Bool))) |
newtype TestBodyHash Source #
Hash of a TestBody
Instances
data TestHeader Source #
TestHeader | |
|
Instances
newtype TestHeaderHash Source #
Hash of a TestHeader
Instances
Ouroboros consensus re-exports
Block | |
|
Instances
Generic (Block slot hash) | |
(Show slot, Show hash) ⇒ Show (Block slot hash) | |
(Eq slot, Eq hash) ⇒ Eq (Block slot hash) | |
(Ord slot, Ord hash) ⇒ Ord (Block slot hash) | |
Defined in Ouroboros.Network.Point compare ∷ Block slot hash → Block slot hash → Ordering # (<) ∷ Block slot hash → Block slot hash → Bool # (<=) ∷ Block slot hash → Block slot hash → Bool # (>) ∷ Block slot hash → Block slot hash → Bool # (>=) ∷ Block slot hash → Block slot hash → Bool # | |
(NoThunks slot, NoThunks hash) ⇒ NoThunks (Block slot hash) | |
type Rep (Block slot hash) | |
Defined in Ouroboros.Network.Point type Rep (Block slot hash) = D1 ('MetaData "Block" "Ouroboros.Network.Point" "ouroboros-network-api-0.11.0.0-51203573fcfcfd3b2c06491320742b9da13f8f293bfcf4fc69f087b3c7b975f1" 'False) (C1 ('MetaCons "Block" 'PrefixI 'True) (S1 ('MetaSel ('Just "blockPointSlot") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 slot) :*: S1 ('MetaSel ('Just "blockPointHash") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 hash))) |
The 0-based index of the block in the blockchain. BlockNo is <= SlotNo and is only equal at slot N if there is a block for every slot where N <= SlotNo.
Instances
FromJSON BlockNo | |
ToJSON BlockNo | |
Bounded BlockNo | |
Enum BlockNo | |
Defined in Cardano.Slotting.Block | |
Generic BlockNo | |
Num BlockNo | |
Show BlockNo | |
FromCBOR BlockNo | |
ToCBOR BlockNo | |
NFData BlockNo | |
Defined in Cardano.Slotting.Block | |
Eq BlockNo | |
Ord BlockNo | |
Hashable BlockNo Source # | |
NoThunks BlockNo | |
ChainOrder BlockNo | |
Defined in Ouroboros.Consensus.Protocol.Abstract type ChainOrderConfig BlockNo Source # | |
Condense BlockNo | |
Serialise BlockNo | |
type Rep BlockNo | |
Defined in Cardano.Slotting.Block type Rep BlockNo = D1 ('MetaData "BlockNo" "Cardano.Slotting.Block" "cardano-slotting-0.2.0.0-9a23f79e0e302e2ea8ebe3129d51bc2e49a139397f4b8d2bbe15b983bdf6811e" 'True) (C1 ('MetaCons "BlockNo" 'PrefixI 'True) (S1 ('MetaSel ('Just "unBlockNo") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word64))) | |
type ChainOrderConfig BlockNo | |
Defined in Ouroboros.Consensus.Protocol.Abstract |
data ChainHash (b ∷ k) Source #
Instances
Chain type
Follower
s can choose to track changes to the "normal" SelectedChain
, or
track the TentativeChain
, which might contain a pipelineable header at the
tip.
data ChainUpdate (block ∷ k) a Source #
A representation of two actions to update a chain: add a block or roll back to a previous point.
The type parameter a
is there to allow a Functor
instance. Typically,
it will be instantiated with block
itself.
Instances
Size of the chunks of the immutable DB
This is the key data structure that drives all layout functions.
TODO: Add support for non-uniform ChunkInfo
https://github.com/IntersectMBO/ouroboros-network/issues/1754
UniformChunkSize !ChunkSize | A single, uniform, chunk size If EBBs are present, the chunk size must line up precisely with the epoch size (that is, the number of regular blocks in the chunk must equal the number of regular blocks in an epoch). |
Instances
Generic ChunkInfo | |
Show ChunkInfo | |
NoThunks ChunkInfo | |
type Rep ChunkInfo | |
Defined in Ouroboros.Consensus.Storage.ImmutableDB.Chunks.Internal type Rep ChunkInfo = D1 ('MetaData "ChunkInfo" "Ouroboros.Consensus.Storage.ImmutableDB.Chunks.Internal" "ouroboros-consensus-0.21.0.0-inplace" 'False) (C1 ('MetaCons "UniformChunkSize" 'PrefixI 'False) (S1 ('MetaSel ('Nothing ∷ Maybe Symbol) 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 ChunkSize))) |
Size of a chunk
The total number of slots available in a chunk is equal to numRegularBlocks
if not
chunkCanContainEBB
, and numRegularBlocks
+ 1
otherwise.
ChunkSize | |
|
Instances
Generic ChunkSize | |
Show ChunkSize | |
NoThunks ChunkSize | |
type Rep ChunkSize | |
Defined in Ouroboros.Consensus.Storage.ImmutableDB.Chunks.Internal type Rep ChunkSize = D1 ('MetaData "ChunkSize" "Ouroboros.Consensus.Storage.ImmutableDB.Chunks.Internal" "ouroboros-consensus-0.21.0.0-inplace" 'False) (C1 ('MetaCons "ChunkSize" 'PrefixI 'True) (S1 ('MetaSel ('Just "chunkCanContainEBB") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Bool) :*: S1 ('MetaSel ('Just "numRegularBlocks") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Word64))) |
An epoch, i.e. the number of the epoch.
Instances
FromJSON EpochNo | |
ToJSON EpochNo | |
Enum EpochNo | |
Defined in Cardano.Slotting.Slot | |
Generic EpochNo | |
Show EpochNo | |
FromCBOR EpochNo | |
ToCBOR EpochNo | |
NFData EpochNo | |
Defined in Cardano.Slotting.Slot | |
Eq EpochNo | |
Ord EpochNo | |
NoThunks EpochNo | |
Condense EpochNo | |
Serialise EpochNo | |
type Rep EpochNo | |
Defined in Cardano.Slotting.Slot type Rep EpochNo = D1 ('MetaData "EpochNo" "Cardano.Slotting.Slot" "cardano-slotting-0.2.0.0-9a23f79e0e302e2ea8ebe3129d51bc2e49a139397f4b8d2bbe15b983bdf6811e" 'True) (C1 ('MetaCons "EpochNo" 'PrefixI 'True) (S1 ('MetaSel ('Just "unEpochNo") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word64))) |
The 0-based index for the Ourboros time slot.