Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
The Ledger DB is responsible for the following tasks:
- Maintaining the in-memory ledger state at the tip: When we try to extend our chain with a new block fitting onto our tip, the block must first be validated using the right ledger state, i.e., the ledger state corresponding to the tip.
Maintaining the past \(k\) in-memory ledger states: we might roll back up to \(k\) blocks when switching to a more preferable fork. Consider the example below:
Our current chain's tip is \(C_2\), but the fork containing blocks with tags \(F_1\), \(F_2\), and \(F_3\) is more preferable. We roll back our chain to the intersection point of the two chains, \(I\), which must be not more than \(k\) blocks back from our current tip. Next, we must validate block \(F_1\) using the ledger state at block \(I\), after which we can validate \(F_2\) using the resulting ledger state, and so on.
This means that we need access to all ledger states of the past \(k\) blocks, i.e., the ledger states corresponding to the volatile part of the current chain. Note that applying a block to a ledger state is not an invertible operation, so it is not possible to simply unapply \(C_1\) and \(C_2\) to obtain \(I\).
Access to the last \(k\) ledger states is not only needed for validating candidate chains, but also by the:
- Local state query server: To query any of the past \(k\) ledger states.
- Chain sync client: To validate headers of a chain that intersects with any of the past \(k\) blocks.
Storing snapshots on disk: To obtain a ledger state for the current tip of the chain, one has to apply all blocks in the chain one-by-one to the initial ledger state. When starting up the system with an on-disk chain containing millions of blocks, all of them would have to be read from disk and applied. This process can take hours, depending on the storage and CPU speed, and is thus too costly to perform on each startup.
For this reason, a recent snapshot of the ledger state should be periodically written to disk. Upon the next startup, that snapshot can be read and used to restore the current ledger state, as well as the past volatile \(k\) ledger states.
(image code)
>>>
import Image.LaTeX.Render
>>>
import Control.Monad
>>>
import System.Directory
>>>
>>>
createDirectoryIfMissing True "docs/haddocks/"
>>>
:{
>>>
either (error . show) pure =<<
>>>
renderToFile "docs/haddocks/ledgerdb-switch.svg" defaultEnv (tikz ["positioning", "arrows"]) "\
>>>
\ \\draw (0, 0) -- (50pt, 0) coordinate (I);\
>>>
\ \\draw (I) -- ++(20pt, 20pt) coordinate (C1) -- ++(20pt, 0) coordinate (C2);\
>>>
\ \\draw (I) -- ++(20pt, -20pt) coordinate (F1) -- ++(20pt, 0) coordinate (F2) -- ++(20pt, 0) coordinate (F3);\
>>>
\ \\node at (I) {$\\bullet$};\
>>>
\ \\node at (C1) {$\\bullet$};\
>>>
\ \\node at (C2) {$\\bullet$};\
>>>
\ \\node at (F1) {$\\bullet$};\
>>>
\ \\node at (F2) {$\\bullet$};\
>>>
\ \\node at (F3) {$\\bullet$};\
>>>
\ \\node at (I) [above left] {$I$};\
>>>
\ \\node at (C1) [above] {$C_1$};\
>>>
\ \\node at (C2) [above] {$C_2$};\
>>>
\ \\node at (F1) [below] {$F_1$};\
>>>
\ \\node at (F2) [below] {$F_2$};\
>>>
\ \\node at (F3) [below] {$F_3$};\
>>>
\ \\draw (60pt, 50pt) node {$\\overbrace{\\hspace{60pt}}$};\
>>>
\ \\draw (60pt, 60pt) node[fill=white] {$k$};\
>>>
\ \\draw [dashed] (30pt, -40pt) -- (30pt, 45pt);"
>>>
:}
Synopsis
- newtype Checkpoint l = Checkpoint {
- unCheckpoint ∷ l
- newtype LedgerDB l = LedgerDB {
- ledgerDbCheckpoints ∷ AnchoredSeq (WithOrigin SlotNo) (Checkpoint l) (Checkpoint l)
- type LedgerDB' blk = LedgerDB (ExtLedgerState blk)
- data LedgerDbCfg l = LedgerDbCfg {}
- configLedgerDb ∷ ConsensusProtocol (BlockProtocol blk) ⇒ TopLevelConfig blk → LedgerDbCfg (ExtLedgerState blk)
- data InitLog blk
- = InitFromGenesis
- | InitFromSnapshot DiskSnapshot (RealPoint blk)
- | InitFailure DiskSnapshot (SnapshotFailure blk) (InitLog blk)
- newtype ReplayStart blk = ReplayStart (Point blk)
- initLedgerDB ∷ ∀ m blk. (IOLike m, LedgerSupportsProtocol blk, InspectLedger blk, HasCallStack) ⇒ Tracer m (ReplayGoal blk → TraceReplayEvent blk) → Tracer m (TraceSnapshotEvent blk) → SomeHasFS m → (∀ s. Decoder s (ExtLedgerState blk)) → (∀ s. Decoder s (HeaderHash blk)) → LedgerDbCfg (ExtLedgerState blk) → m (ExtLedgerState blk) → StreamAPI m blk blk → m (InitLog blk, LedgerDB' blk, Word64)
- newtype ReplayGoal blk = ReplayGoal (Point blk)
- data TraceReplayEvent blk
- = ReplayFromGenesis (ReplayGoal blk)
- | ReplayFromSnapshot DiskSnapshot (ReplayStart blk) (ReplayGoal blk)
- | ReplayedBlock (RealPoint blk) [LedgerEvent blk] (ReplayStart blk) (ReplayGoal blk)
- decorateReplayTracerWithGoal ∷ Point blk → Tracer m (TraceReplayEvent blk) → Tracer m (ReplayGoal blk → TraceReplayEvent blk)
- decorateReplayTracerWithStart ∷ Point blk → Tracer m (ReplayGoal blk → TraceReplayEvent blk) → Tracer m (ReplayStart blk → ReplayGoal blk → TraceReplayEvent blk)
- ledgerDbAnchor ∷ LedgerDB l → l
- ledgerDbCurrent ∷ GetTip l ⇒ LedgerDB l → l
- ledgerDbIsSaturated ∷ GetTip l ⇒ SecurityParam → LedgerDB l → Bool
- ledgerDbMaxRollback ∷ GetTip l ⇒ LedgerDB l → Word64
- ledgerDbPast ∷ (HasHeader blk, IsLedger l, HeaderHash l ~ HeaderHash blk) ⇒ Point blk → LedgerDB l → Maybe l
- ledgerDbSnapshots ∷ LedgerDB l → [(Word64, l)]
- ledgerDbTip ∷ GetTip l ⇒ LedgerDB l → Point l
- ledgerDbWithAnchor ∷ GetTip l ⇒ l → LedgerDB l
- data AnnLedgerError l blk = AnnLedgerError {
- annLedgerState ∷ LedgerDB l
- annLedgerErrRef ∷ RealPoint blk
- annLedgerErr ∷ LedgerErr l
- type AnnLedgerError' blk = AnnLedgerError (ExtLedgerState blk) blk
- data Ap m l blk c where
- ReapplyVal ∷ blk → Ap m l blk ()
- ApplyVal ∷ blk → Ap m l blk (ThrowsLedgerError m l blk)
- ReapplyRef ∷ RealPoint blk → Ap m l blk (ResolvesBlocks m blk)
- ApplyRef ∷ RealPoint blk → Ap m l blk (ResolvesBlocks m blk, ThrowsLedgerError m l blk)
- Weaken ∷ (c' ⇒ c) ⇒ Ap m l blk c → Ap m l blk c'
- data ExceededRollback = ExceededRollback {}
- class Monad m ⇒ ThrowsLedgerError m l blk where
- throwLedgerError ∷ LedgerDB l → RealPoint blk → LedgerErr l → m a
- defaultThrowLedgerErrors ∷ ExceptT (AnnLedgerError l blk) m a → m (Either (AnnLedgerError l blk) a)
- type ResolveBlock m blk = RealPoint blk → m blk
- class Monad m ⇒ ResolvesBlocks m blk | m → blk where
- doResolveBlock ∷ ResolveBlock m blk
- defaultResolveBlocks ∷ ResolveBlock m blk → ReaderT (ResolveBlock m blk) m a → m a
- defaultResolveWithErrors ∷ ResolveBlock m blk → ExceptT (AnnLedgerError l blk) (ReaderT (ResolveBlock m blk) m) a → m (Either (AnnLedgerError l blk) a)
- ledgerDbBimap ∷ Anchorable (WithOrigin SlotNo) a b ⇒ (l → a) → (l → b) → LedgerDB l → AnchoredSeq (WithOrigin SlotNo) a b
- ledgerDbPrune ∷ GetTip l ⇒ SecurityParam → LedgerDB l → LedgerDB l
- ledgerDbPush ∷ ∀ m c l blk. (ApplyBlock l blk, Monad m, c) ⇒ LedgerDbCfg l → Ap m l blk c → LedgerDB l → m (LedgerDB l)
- ledgerDbSwitch ∷ (ApplyBlock l blk, Monad m, c) ⇒ LedgerDbCfg l → Word64 → (UpdateLedgerDbTraceEvent blk → m ()) → [Ap m l blk c] → LedgerDB l → m (Either ExceededRollback (LedgerDB l))
- ledgerDbPush' ∷ ApplyBlock l blk ⇒ LedgerDbCfg l → blk → LedgerDB l → LedgerDB l
- ledgerDbPushMany' ∷ ApplyBlock l blk ⇒ LedgerDbCfg l → [blk] → LedgerDB l → LedgerDB l
- ledgerDbSwitch' ∷ ∀ l blk. ApplyBlock l blk ⇒ LedgerDbCfg l → Word64 → [blk] → LedgerDB l → Maybe (LedgerDB l)
- newtype PushGoal blk = PushGoal {
- unPushGoal ∷ RealPoint blk
- newtype PushStart blk = PushStart {
- unPushStart ∷ RealPoint blk
- newtype Pushing blk = Pushing {}
- data UpdateLedgerDbTraceEvent blk = StartedPushingBlockToTheLedgerDb !(PushStart blk) (PushGoal blk) !(Pushing blk)
- data DiskSnapshot = DiskSnapshot {}
- data SnapshotFailure blk
- diskSnapshotIsTemporary ∷ DiskSnapshot → Bool
- listSnapshots ∷ Monad m ⇒ SomeHasFS m → m [DiskSnapshot]
- readSnapshot ∷ ∀ m blk. IOLike m ⇒ SomeHasFS m → (∀ s. Decoder s (ExtLedgerState blk)) → (∀ s. Decoder s (HeaderHash blk)) → DiskSnapshot → ExceptT ReadIncrementalErr m (ExtLedgerState blk)
- takeSnapshot ∷ ∀ m blk. (MonadThrow m, MonadMonotonicTime m, IsLedger (LedgerState blk)) ⇒ Tracer m (TraceSnapshotEvent blk) → SomeHasFS m → (ExtLedgerState blk → Encoding) → ExtLedgerState blk → m (Maybe (DiskSnapshot, RealPoint blk))
- trimSnapshots ∷ Monad m ⇒ Tracer m (TraceSnapshotEvent r) → SomeHasFS m → DiskPolicy → m [DiskSnapshot]
- writeSnapshot ∷ ∀ m blk. MonadThrow m ⇒ SomeHasFS m → (ExtLedgerState blk → Encoding) → DiskSnapshot → ExtLedgerState blk → m ()
- decodeSnapshotBackwardsCompatible ∷ ∀ l blk. Proxy blk → (∀ s. Decoder s l) → (∀ s. Decoder s (HeaderHash blk)) → ∀ s. Decoder s l
- deleteSnapshot ∷ HasCallStack ⇒ SomeHasFS m → DiskSnapshot → m ()
- encodeSnapshot ∷ (l → Encoding) → l → Encoding
- snapshotToFileName ∷ DiskSnapshot → String
- snapshotToPath ∷ DiskSnapshot → FsPath
- data TraceSnapshotEvent blk
- data DiskPolicy = DiskPolicy {}
- data DiskPolicyArgs = DiskPolicyArgs SnapshotInterval NumOfDiskSnapshots
- data NumOfDiskSnapshots
- data SnapshotInterval
- data TimeSinceLast time
- = NoSnapshotTakenYet
- | TimeSinceLast time
- defaultDiskPolicyArgs ∷ DiskPolicyArgs
- mkDiskPolicy ∷ SecurityParam → DiskPolicyArgs → DiskPolicy
LedgerDB
newtype Checkpoint l Source #
Internal newtype wrapper around a ledger state l
so that we can define a
non-blanket Anchorable
instance.
Instances
Internal state of the ledger DB
The ledger DB looks like
anchor |> snapshots <| current
where anchor
records the oldest known snapshot and current
the most
recent. The anchor is the oldest point we can roll back to.
We take a snapshot after each block is applied and keep in memory a window
of the last k
snapshots. We have verified empirically (#1936) that the
overhead of keeping k
snapshots in memory is small, i.e., about 5%
compared to keeping a snapshot every 100 blocks. This is thanks to sharing
between consecutive snapshots.
As an example, suppose we have k = 6
. The ledger DB grows as illustrated
below, where we indicate the anchor number of blocks, the stored snapshots,
and the current ledger.
anchor |> # [ snapshots ] <| tip --------------------------------------------------------------------------- G |> (0) [ ] <| G G |> (1) [ L1] <| L1 G |> (2) [ L1, L2] <| L2 G |> (3) [ L1, L2, L3] <| L3 G |> (4) [ L1, L2, L3, L4] <| L4 G |> (5) [ L1, L2, L3, L4, L5] <| L5 G |> (6) [ L1, L2, L3, L4, L5, L6] <| L6 L1 |> (6) [ L2, L3, L4, L5, L6, L7] <| L7 L2 |> (6) [ L3, L4, L5, L6, L7, L8] <| L8 L3 |> (6) [ L4, L5, L6, L7, L8, L9] <| L9 (*) L4 |> (6) [ L5, L6, L7, L8, L9, L10] <| L10 L5 |> (6) [*L6, L7, L8, L9, L10, L11] <| L11 L6 |> (6) [ L7, L8, L9, L10, L11, L12] <| L12 L7 |> (6) [ L8, L9, L10, L12, L12, L13] <| L13 L8 |> (6) [ L9, L10, L12, L12, L13, L14] <| L14
The ledger DB must guarantee that at all times we are able to roll back k
blocks. For example, if we are on line (*), and roll back 6 blocks, we get
L3 |> []
LedgerDB | |
|
Instances
Generic (LedgerDB l) Source # | |
Show l ⇒ Show (LedgerDB l) Source # | |
Eq l ⇒ Eq (LedgerDB l) Source # | |
NoThunks l ⇒ NoThunks (LedgerDB l) Source # | |
IsLedger l ⇒ GetTip (LedgerDB l) Source # | |
type HeaderHash (LedgerDB l ∷ Type) Source # | |
type Rep (LedgerDB l) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.LedgerDB type Rep (LedgerDB l) = D1 ('MetaData "LedgerDB" "Ouroboros.Consensus.Storage.LedgerDB.LedgerDB" "ouroboros-consensus-0.21.0.0-inplace" 'True) (C1 ('MetaCons "LedgerDB" 'PrefixI 'True) (S1 ('MetaSel ('Just "ledgerDbCheckpoints") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (AnchoredSeq (WithOrigin SlotNo) (Checkpoint l) (Checkpoint l))))) |
type LedgerDB' blk = LedgerDB (ExtLedgerState blk) Source #
data LedgerDbCfg l Source #
Instances
Generic (LedgerDbCfg l) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.LedgerDB type Rep (LedgerDbCfg l) ∷ Type → Type # from ∷ LedgerDbCfg l → Rep (LedgerDbCfg l) x # to ∷ Rep (LedgerDbCfg l) x → LedgerDbCfg l # | |
NoThunks (LedgerCfg l) ⇒ NoThunks (LedgerDbCfg l) Source # | |
type Rep (LedgerDbCfg l) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.LedgerDB type Rep (LedgerDbCfg l) = D1 ('MetaData "LedgerDbCfg" "Ouroboros.Consensus.Storage.LedgerDB.LedgerDB" "ouroboros-consensus-0.21.0.0-inplace" 'False) (C1 ('MetaCons "LedgerDbCfg" 'PrefixI 'True) (S1 ('MetaSel ('Just "ledgerDbCfgSecParam") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 SecurityParam) :*: S1 ('MetaSel ('Just "ledgerDbCfg") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (LedgerCfg l)))) |
configLedgerDb ∷ ConsensusProtocol (BlockProtocol blk) ⇒ TopLevelConfig blk → LedgerDbCfg (ExtLedgerState blk) Source #
Initialization
Initialization log
The initialization log records which snapshots from disk were considered, in which order, and why some snapshots were rejected. It is primarily useful for monitoring purposes.
InitFromGenesis | Defaulted to initialization from genesis NOTE: Unless the blockchain is near genesis, we should see this only if data corrupted occurred. |
InitFromSnapshot DiskSnapshot (RealPoint blk) | Used a snapshot corresponding to the specified tip |
InitFailure DiskSnapshot (SnapshotFailure blk) (InitLog blk) | Initialization skipped a snapshot We record the reason why it was skipped. NOTE: We should only see this if data corrupted occurred. |
Instances
newtype ReplayStart blk Source #
Which point the replay started from
ReplayStart (Point blk) |
Instances
StandardHash blk ⇒ Show (ReplayStart blk) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Init showsPrec ∷ Int → ReplayStart blk → ShowS # show ∷ ReplayStart blk → String # showList ∷ [ReplayStart blk] → ShowS # | |
StandardHash blk ⇒ Eq (ReplayStart blk) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Init (==) ∷ ReplayStart blk → ReplayStart blk → Bool # (/=) ∷ ReplayStart blk → ReplayStart blk → Bool # |
∷ ∀ m blk. (IOLike m, LedgerSupportsProtocol blk, InspectLedger blk, HasCallStack) | |
⇒ Tracer m (ReplayGoal blk → TraceReplayEvent blk) | |
→ Tracer m (TraceSnapshotEvent blk) | |
→ SomeHasFS m | |
→ (∀ s. Decoder s (ExtLedgerState blk)) | |
→ (∀ s. Decoder s (HeaderHash blk)) | |
→ LedgerDbCfg (ExtLedgerState blk) | |
→ m (ExtLedgerState blk) | Genesis ledger state |
→ StreamAPI m blk blk | |
→ m (InitLog blk, LedgerDB' blk, Word64) |
Initialize the ledger DB from the most recent snapshot on disk
If no such snapshot can be found, use the genesis ledger DB. Returns the initialized DB as well as the block reference corresponding to the snapshot we found on disk (the latter primarily for testing/monitoring purposes).
We do not catch any exceptions thrown during streaming; should any be
thrown, it is the responsibility of the ChainDB
to catch these
and trigger (further) validation. We only discard snapshots if
- We cannot deserialise them, or
- they are ahead of the chain
It is possible that the Ledger DB will not be able to roll back k
blocks
after initialization if the chain has been truncated (data corruption).
We do not attempt to use multiple ledger states from disk to construct the ledger DB. Instead we load only a single ledger state from disk, and compute all subsequent ones. This is important, because the ledger states obtained in this way will (hopefully) share much of their memory footprint with their predecessors.
Trace
newtype ReplayGoal blk Source #
Which point the replay is expected to end at
ReplayGoal (Point blk) |
Instances
StandardHash blk ⇒ Show (ReplayGoal blk) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Init showsPrec ∷ Int → ReplayGoal blk → ShowS # show ∷ ReplayGoal blk → String # showList ∷ [ReplayGoal blk] → ShowS # | |
StandardHash blk ⇒ Eq (ReplayGoal blk) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Init (==) ∷ ReplayGoal blk → ReplayGoal blk → Bool # (/=) ∷ ReplayGoal blk → ReplayGoal blk → Bool # |
data TraceReplayEvent blk Source #
Events traced while replaying blocks against the ledger to bring it up to date w.r.t. the tip of the ImmutableDB during initialisation. As this process takes a while, we trace events to inform higher layers of our progress.
ReplayFromGenesis | There were no LedgerDB snapshots on disk, so we're replaying all blocks starting from Genesis against the initial ledger. |
| |
ReplayFromSnapshot | |
| |
ReplayedBlock | |
|
Instances
decorateReplayTracerWithGoal Source #
∷ Point blk | Tip of the ImmutableDB |
→ Tracer m (TraceReplayEvent blk) | |
→ Tracer m (ReplayGoal blk → TraceReplayEvent blk) |
Add the tip of the Immutable DB to the trace event
Between the tip of the immutable DB and the point of the starting block, the node could (if it so desired) easily compute a "percentage complete".
decorateReplayTracerWithStart Source #
∷ Point blk | Starting point of the replay |
→ Tracer m (ReplayGoal blk → TraceReplayEvent blk) | |
→ Tracer m (ReplayStart blk → ReplayGoal blk → TraceReplayEvent blk) |
Add the block at which a replay started.
This allows to compute a "percentage complete" when tracing the events.
Querying
ledgerDbAnchor ∷ LedgerDB l → l Source #
Information about the state of the ledger at the anchor
ledgerDbCurrent ∷ GetTip l ⇒ LedgerDB l → l Source #
The ledger state at the tip of the chain
ledgerDbIsSaturated ∷ GetTip l ⇒ SecurityParam → LedgerDB l → Bool Source #
Have we seen at least k
blocks?
ledgerDbMaxRollback ∷ GetTip l ⇒ LedgerDB l → Word64 Source #
How many blocks can we currently roll back?
ledgerDbPast ∷ (HasHeader blk, IsLedger l, HeaderHash l ~ HeaderHash blk) ⇒ Point blk → LedgerDB l → Maybe l Source #
ledgerDbSnapshots ∷ LedgerDB l → [(Word64, l)] Source #
All snapshots currently stored by the ledger DB (new to old)
This also includes the snapshot at the anchor. For each snapshot we also return the distance from the tip.
ledgerDbTip ∷ GetTip l ⇒ LedgerDB l → Point l Source #
Reference to the block at the tip of the chain
Updates
Construct
ledgerDbWithAnchor ∷ GetTip l ⇒ l → LedgerDB l Source #
Ledger DB starting at the specified ledger state
Applying blocks
data AnnLedgerError l blk Source #
Annotated ledger errors
AnnLedgerError | |
|
Instances
Monad m ⇒ ThrowsLedgerError (ExceptT (AnnLedgerError l blk) m) l blk Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Update throwLedgerError ∷ LedgerDB l → RealPoint blk → LedgerErr l → ExceptT (AnnLedgerError l blk) m a Source # |
type AnnLedgerError' blk = AnnLedgerError (ExtLedgerState blk) blk Source #
data Ap m l blk c where Source #
Ap
is used to pass information about blocks to ledger DB updates
The constructors serve two purposes:
- Specify the various parameters a. Are we passing the block by value or by reference? b. Are we applying or reapplying the block?
- Compute the constraint
c
on the monadm
in order to run the query: a. If we are passing a block by reference, we must be able to resolve it. b. If we are applying rather than reapplying, we might have ledger errors.
ReapplyVal ∷ blk → Ap m l blk () | |
ApplyVal ∷ blk → Ap m l blk (ThrowsLedgerError m l blk) | |
ReapplyRef ∷ RealPoint blk → Ap m l blk (ResolvesBlocks m blk) | |
ApplyRef ∷ RealPoint blk → Ap m l blk (ResolvesBlocks m blk, ThrowsLedgerError m l blk) | |
Weaken ∷ (c' ⇒ c) ⇒ Ap m l blk c → Ap m l blk c' |
This is primarily useful when combining multiple |
data ExceededRollback Source #
Exceeded maximum rollback supported by the current ledger DB state
Under normal circumstances this will not arise. It can really only happen in the presence of data corruption (or when switching to a shorter fork, but that is disallowed by all currently known Ouroboros protocols).
Records both the supported and the requested rollback.
class Monad m ⇒ ThrowsLedgerError m l blk where Source #
Instances
Monad m ⇒ ThrowsLedgerError (ExceptT (AnnLedgerError l blk) m) l blk Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Update throwLedgerError ∷ LedgerDB l → RealPoint blk → LedgerErr l → ExceptT (AnnLedgerError l blk) m a Source # |
defaultThrowLedgerErrors ∷ ExceptT (AnnLedgerError l blk) m a → m (Either (AnnLedgerError l blk) a) Source #
Block resolution
type ResolveBlock m blk = RealPoint blk → m blk Source #
Resolve a block
Resolving a block reference to the actual block lives in m
because
it might need to read the block from disk (and can therefore not be
done inside an STM transaction).
NOTE: The ledger DB will only ask the ChainDB
for blocks it knows
must exist. If the ChainDB
is unable to fulfill the request, data
corruption must have happened and the ChainDB
should trigger
validation mode.
class Monad m ⇒ ResolvesBlocks m blk | m → blk where Source #
Monads in which we can resolve blocks
To guide type inference, we insist that we must be able to infer the type of the block we are resolving from the type of the monad.
doResolveBlock ∷ ResolveBlock m blk Source #
Instances
Monad m ⇒ ResolvesBlocks (ExceptT e (ReaderT (ResolveBlock m blk) m)) blk Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Update doResolveBlock ∷ ResolveBlock (ExceptT e (ReaderT (ResolveBlock m blk) m)) blk Source # | |
Monad m ⇒ ResolvesBlocks (ReaderT (ResolveBlock m blk) m) blk Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.Update doResolveBlock ∷ ResolveBlock (ReaderT (ResolveBlock m blk) m) blk Source # |
defaultResolveBlocks ∷ ResolveBlock m blk → ReaderT (ResolveBlock m blk) m a → m a Source #
Operations
defaultResolveWithErrors ∷ ResolveBlock m blk → ExceptT (AnnLedgerError l blk) (ReaderT (ResolveBlock m blk) m) a → m (Either (AnnLedgerError l blk) a) Source #
ledgerDbBimap ∷ Anchorable (WithOrigin SlotNo) a b ⇒ (l → a) → (l → b) → LedgerDB l → AnchoredSeq (WithOrigin SlotNo) a b Source #
Transform the underlying AnchoredSeq
using the given functions.
ledgerDbPrune ∷ GetTip l ⇒ SecurityParam → LedgerDB l → LedgerDB l Source #
Prune snapshots until at we have at most k
snapshots in the LedgerDB,
excluding the snapshots stored at the anchor.
ledgerDbPush ∷ ∀ m c l blk. (ApplyBlock l blk, Monad m, c) ⇒ LedgerDbCfg l → Ap m l blk c → LedgerDB l → m (LedgerDB l) Source #
∷ (ApplyBlock l blk, Monad m, c) | |
⇒ LedgerDbCfg l | |
→ Word64 | How many blocks to roll back |
→ (UpdateLedgerDbTraceEvent blk → m ()) | |
→ [Ap m l blk c] | New blocks to apply |
→ LedgerDB l | |
→ m (Either ExceededRollback (LedgerDB l)) |
Switch to a fork
Pure API
ledgerDbPush' ∷ ApplyBlock l blk ⇒ LedgerDbCfg l → blk → LedgerDB l → LedgerDB l Source #
ledgerDbPushMany' ∷ ApplyBlock l blk ⇒ LedgerDbCfg l → [blk] → LedgerDB l → LedgerDB l Source #
ledgerDbSwitch' ∷ ∀ l blk. ApplyBlock l blk ⇒ LedgerDbCfg l → Word64 → [blk] → LedgerDB l → Maybe (LedgerDB l) Source #
Trace
PushGoal | |
|
Instances
StandardHash blk ⇒ Show (PushGoal blk) Source # | |
StandardHash blk ⇒ Eq (PushGoal blk) Source # | |
newtype PushStart blk Source #
PushStart | |
|
Instances
StandardHash blk ⇒ Show (PushStart blk) Source # | |
StandardHash blk ⇒ Eq (PushStart blk) Source # | |
Instances
StandardHash blk ⇒ Show (Pushing blk) Source # | |
StandardHash blk ⇒ Eq (Pushing blk) Source # | |
data UpdateLedgerDbTraceEvent blk Source #
StartedPushingBlockToTheLedgerDb | Event fired when we are about to push a block to the LedgerDB |
Instances
Snapshots
data DiskSnapshot Source #
DiskSnapshot | |
|
Instances
Read from disk
data SnapshotFailure blk Source #
InitFailureRead ReadIncrementalErr | We failed to deserialise the snapshot This can happen due to data corruption in the ledger DB. |
InitFailureTooRecent (RealPoint blk) | This snapshot is too recent (ahead of the tip of the chain) |
InitFailureGenesis | This snapshot was of the ledger state at genesis, even though we never take snapshots at genesis, so this is unexpected. |
Instances
diskSnapshotIsTemporary ∷ DiskSnapshot → Bool Source #
The snapshots that are periodically created are temporary, they will be deleted when trimming
listSnapshots ∷ Monad m ⇒ SomeHasFS m → m [DiskSnapshot] Source #
List on-disk snapshots, highest number first.
readSnapshot ∷ ∀ m blk. IOLike m ⇒ SomeHasFS m → (∀ s. Decoder s (ExtLedgerState blk)) → (∀ s. Decoder s (HeaderHash blk)) → DiskSnapshot → ExceptT ReadIncrementalErr m (ExtLedgerState blk) Source #
Read snapshot from disk
Write to disk
takeSnapshot ∷ ∀ m blk. (MonadThrow m, MonadMonotonicTime m, IsLedger (LedgerState blk)) ⇒ Tracer m (TraceSnapshotEvent blk) → SomeHasFS m → (ExtLedgerState blk → Encoding) → ExtLedgerState blk → m (Maybe (DiskSnapshot, RealPoint blk)) Source #
Take a snapshot of the oldest ledger state in the ledger DB
We write the oldest ledger state to disk because the intention is to only
write ledger states to disk that we know to be immutable. Primarily for
testing purposes, takeSnapshot
returns the block reference corresponding
to the snapshot that we wrote.
If a snapshot with the same number already exists on disk or if the tip is at genesis, no snapshot is taken.
Note that an EBB can have the same slot number and thus snapshot number as the block after it. This doesn't matter. The one block difference in the ledger state doesn't warrant an additional snapshot. The number in the name of the snapshot is only indicative, we don't rely on it being correct.
NOTE: This is a lower-level API that takes a snapshot independent from
whether this snapshot corresponds to a state that is more than k
back.
TODO: Should we delete the file if an error occurs during writing?
trimSnapshots ∷ Monad m ⇒ Tracer m (TraceSnapshotEvent r) → SomeHasFS m → DiskPolicy → m [DiskSnapshot] Source #
Trim the number of on disk snapshots so that at most onDiskNumSnapshots
snapshots are stored on disk. The oldest snapshots are deleted.
The deleted snapshots are returned.
writeSnapshot ∷ ∀ m blk. MonadThrow m ⇒ SomeHasFS m → (ExtLedgerState blk → Encoding) → DiskSnapshot → ExtLedgerState blk → m () Source #
Write snapshot to disk
Low-level API (primarily exposed for testing)
decodeSnapshotBackwardsCompatible ∷ ∀ l blk. Proxy blk → (∀ s. Decoder s l) → (∀ s. Decoder s (HeaderHash blk)) → ∀ s. Decoder s l Source #
To remain backwards compatible with existing snapshots stored on disk, we must accept the old format as well as the new format.
The old format:
* The tip: WithOrigin (RealPoint blk)
* The chain length: Word64
* The ledger state: l
The new format is described by snapshotEncodingVersion1
.
This decoder will accept and ignore them. The encoder (encodeSnapshot
) will
no longer encode them.
deleteSnapshot ∷ HasCallStack ⇒ SomeHasFS m → DiskSnapshot → m () Source #
Delete snapshot from disk
encodeSnapshot ∷ (l → Encoding) → l → Encoding Source #
Encoder to be used in combination with decodeSnapshotBackwardsCompatible
.
Trace
data TraceSnapshotEvent blk Source #
InvalidSnapshot DiskSnapshot (SnapshotFailure blk) | An on disk snapshot was skipped because it was invalid. |
TookSnapshot DiskSnapshot (RealPoint blk) EnclosingTimed | A snapshot was written to disk. |
DeletedSnapshot DiskSnapshot | An old or invalid on-disk snapshot was deleted |
Instances
Disk policy
data DiskPolicy Source #
On-disk policy
We only write ledger states that are older than k
blocks to disk (that is,
snapshots that are guaranteed valid). The on-disk policy determines how often
we write to disk and how many checkpoints we keep.
DiskPolicy | |
|
Instances
data NumOfDiskSnapshots Source #
Number of snapshots to be stored on disk. This is either the default value
as determined by the DiskPolicy, or it is provided by the user. See the
DiskPolicy
documentation for more information.
Instances
Generic NumOfDiskSnapshots Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy type Rep NumOfDiskSnapshots ∷ Type → Type # | |
Show NumOfDiskSnapshots Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy showsPrec ∷ Int → NumOfDiskSnapshots → ShowS # show ∷ NumOfDiskSnapshots → String # showList ∷ [NumOfDiskSnapshots] → ShowS # | |
Eq NumOfDiskSnapshots Source # | |
type Rep NumOfDiskSnapshots Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy type Rep NumOfDiskSnapshots = D1 ('MetaData "NumOfDiskSnapshots" "Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy" "ouroboros-consensus-0.21.0.0-inplace" 'False) (C1 ('MetaCons "DefaultNumOfDiskSnapshots" 'PrefixI 'False) (U1 ∷ Type → Type) :+: C1 ('MetaCons "RequestedNumOfDiskSnapshots" 'PrefixI 'False) (S1 ('MetaSel ('Nothing ∷ Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Word))) |
data SnapshotInterval Source #
Length of time, requested by the user, that has to pass after which a snapshot is taken. It can be:
- either explicitly provided by user in seconds
- or default value can be requested - the specific DiskPolicy determines
what that is exactly, see
mkDiskPolicy
as an example
Instances
Generic SnapshotInterval Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy type Rep SnapshotInterval ∷ Type → Type # from ∷ SnapshotInterval → Rep SnapshotInterval x # to ∷ Rep SnapshotInterval x → SnapshotInterval # | |
Show SnapshotInterval Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy showsPrec ∷ Int → SnapshotInterval → ShowS # show ∷ SnapshotInterval → String # showList ∷ [SnapshotInterval] → ShowS # | |
Eq SnapshotInterval Source # | |
type Rep SnapshotInterval Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy type Rep SnapshotInterval = D1 ('MetaData "SnapshotInterval" "Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy" "ouroboros-consensus-0.21.0.0-inplace" 'False) (C1 ('MetaCons "DefaultSnapshotInterval" 'PrefixI 'False) (U1 ∷ Type → Type) :+: C1 ('MetaCons "RequestedSnapshotInterval" 'PrefixI 'False) (S1 ('MetaSel ('Nothing ∷ Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 DiffTime))) |
data TimeSinceLast time Source #
Instances
Functor TimeSinceLast Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy fmap ∷ (a → b) → TimeSinceLast a → TimeSinceLast b # (<$) ∷ a → TimeSinceLast b → TimeSinceLast a # | |
Show time ⇒ Show (TimeSinceLast time) Source # | |
Defined in Ouroboros.Consensus.Storage.LedgerDB.DiskPolicy showsPrec ∷ Int → TimeSinceLast time → ShowS # show ∷ TimeSinceLast time → String # showList ∷ [TimeSinceLast time] → ShowS # |
defaultDiskPolicyArgs ∷ DiskPolicyArgs Source #
Default on-disk policy arguments suitable to use with cardano-node