ouroboros-consensus-0.1.0.0: Consensus layer for the Ouroboros blockchain protocol
Safe HaskellNone
LanguageHaskell2010

Ouroboros.Consensus.Storage.LedgerDB.InMemory

Synopsis

LedgerDB proper

data LedgerDB l r Source #

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 |> []

Instances

Instances details
IsLedger l => GetTip (Ticked (LedgerDB l r)) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

getTip :: Ticked (LedgerDB l r) -> Point (Ticked (LedgerDB l r)) Source #

(Eq r, Eq l) => Eq (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

(==) :: LedgerDB l r -> LedgerDB l r -> Bool #

(/=) :: LedgerDB l r -> LedgerDB l r -> Bool #

(Show r, Show l) => Show (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

showsPrec :: Int -> LedgerDB l r -> ShowS #

show :: LedgerDB l r -> String #

showList :: [LedgerDB l r] -> ShowS #

Generic (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Associated Types

type Rep (LedgerDB l r) :: Type -> Type #

Methods

from :: LedgerDB l r -> Rep (LedgerDB l r) x #

to :: Rep (LedgerDB l r) x -> LedgerDB l r #

(NoThunks r, NoThunks l) => NoThunks (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

(IsLedger l, Show r, Eq r, NoThunks r) => IsLedger (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Associated Types

type LedgerErr (LedgerDB l r) Source #

IsLedger l => GetTip (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

getTip :: LedgerDB l r -> Point (LedgerDB l r) Source #

ApplyBlock l blk => ApplyBlock (LedgerDB l (RealPoint blk)) blk Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type Rep (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type Rep (LedgerDB l r)
type HeaderHash (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

data Ticked (LedgerDB l r) Source #

Ticking the ledger DB just ticks the current state

We don't push the new state into the DB until we apply a block.

Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type LedgerErr (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type LedgerCfg (LedgerDB l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

newtype LedgerDbParams Source #

Constructors

LedgerDbParams 

Fields

Instances

Instances details
Eq LedgerDbParams Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Show LedgerDbParams Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Generic LedgerDbParams Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Associated Types

type Rep LedgerDbParams :: Type -> Type #

NoThunks LedgerDbParams Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type Rep LedgerDbParams Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type Rep LedgerDbParams = D1 ('MetaData "LedgerDbParams" "Ouroboros.Consensus.Storage.LedgerDB.InMemory" "ouroboros-consensus-0.1.0.0-GfJNvFcM6lj2s5utKAUPEp" 'True) (C1 ('MetaCons "LedgerDbParams" 'PrefixI 'True) (S1 ('MetaSel ('Just "ledgerDbSecurityParam") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 SecurityParam)))

ledgerDbWithAnchor :: LedgerDbParams -> ChainSummary l r -> LedgerDB l r Source #

Ledger DB starting at the specified ledger state

ChainSummary

data ChainSummary l r Source #

Summary of the chain at a particular point in time

Constructors

ChainSummary 

Fields

Instances

Instances details
(Eq r, Eq l) => Eq (ChainSummary l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

(==) :: ChainSummary l r -> ChainSummary l r -> Bool #

(/=) :: ChainSummary l r -> ChainSummary l r -> Bool #

(Show r, Show l) => Show (ChainSummary l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Generic (ChainSummary l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Associated Types

type Rep (ChainSummary l r) :: Type -> Type #

Methods

from :: ChainSummary l r -> Rep (ChainSummary l r) x #

to :: Rep (ChainSummary l r) x -> ChainSummary l r #

(NoThunks r, NoThunks l) => NoThunks (ChainSummary l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

(Serialise l, Serialise r) => Serialise (ChainSummary l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type Rep (ChainSummary l r) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

type Rep (ChainSummary l r) = D1 ('MetaData "ChainSummary" "Ouroboros.Consensus.Storage.LedgerDB.InMemory" "ouroboros-consensus-0.1.0.0-GfJNvFcM6lj2s5utKAUPEp" 'False) (C1 ('MetaCons "ChainSummary" 'PrefixI 'True) (S1 ('MetaSel ('Just "csTip") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 (WithOrigin r)) :*: (S1 ('MetaSel ('Just "csLength") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Word64) :*: S1 ('MetaSel ('Just "csLedger") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 l))))

decodeChainSummary :: (forall s. Decoder s l) -> (forall s. Decoder s r) -> forall s. Decoder s (ChainSummary l r) Source #

Queries

ledgerDbCurrent :: LedgerDB l r -> l Source #

The ledger state at the tip of the chain

ledgerDbTip :: LedgerDB l r -> WithOrigin r Source #

Reference to the block at the tip of the chain

ledgerDbAnchor :: LedgerDB l r -> ChainSummary l r Source #

Information about the state of the ledger before

Past ledger states

ledgerDbPast :: forall l r ro. (Ord ro, Eq r) => (r -> ro) -> WithOrigin r -> LedgerDB l r -> Maybe l Source #

Get a past ledger state

\( O(\log n * \log n) \).

When no Checkpoint (or anchor) has the given WithOrigin r, Nothing is returned.

To avoid a linear search on the checkpoints (typically 2160 of them), we do a binary search benefitting from the cheap splits of the underlying StrictSeq \( O(\log n) \).

For a binary search, the checkpoints have to be ordered by r. In practice, we'll use RealPoint for r, which, because of the existence of EBBs, doesn't have a reliable ordering: it orders first on SlotNo, which is correct. But in case of a tie, it will look at the hash, which is not what we need: an EBB has the same slot as the block after it, so we'd want the RealPoint of an EBB to be less than the RealPoint of the regular block in the same slot. But the decision is made based on the hash, so we won't get a reliable answer.

Therefore, we take a projection refOrder :: r -> ro as an argument. The ro type should have a correct ordering, so that the list below is correctly ordered:

map (refOrder . cpBlock) $ Seq.toList (ledgerDbCheckpoints db)

When instantiating r to RealPoint, one should use realPointSlot as refOrder.

Note: we don't use fingertree for the checkpoints (with its search operation we could use here) because we'd have to impose more constraints on the r type. We could do an interpolation search if we assume more about the ro parameter (SlotNo), but that would be more complicated.

ledgerDbPastLedgers :: (l -> a) -> LedgerDB l r -> (a, StrictSeq a) Source #

Apply the given function to all past ledgers in the LedgerDB, including the one stored at the anchor.

\( O(n) \)

Running updates

data Ap :: (Type -> Type) -> Type -> Type -> Type -> Constraint -> Type 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 monad m 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.

Constructors

ReapplyVal :: r -> b -> Ap m l r b () 
ApplyVal :: r -> b -> Ap m l r b (ThrowsLedgerError l r m) 
ReapplyRef :: r -> Ap m l r b (ResolvesBlocks r b m) 
ApplyRef :: r -> Ap m l r b (ResolvesBlocks r b m, ThrowsLedgerError l r m) 
Weaken :: (c' => c) => Ap m l r b c -> Ap m l r b c'

Weaken increases the constraint on the monad m.

This is primarily useful when combining multiple Aps in a single homogeneous structure.

data AnnLedgerError l r Source #

Annotated ledger errors

Constructors

AnnLedgerError 

Fields

Instances

Instances details
Monad m => ThrowsLedgerError l r (ExceptT (AnnLedgerError l r) m) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

throwLedgerError :: LedgerDB l r -> r -> LedgerErr l -> ExceptT (AnnLedgerError l r) m a Source #

type ResolveBlock m r b = r -> m b 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 r b m | m -> b 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.

Methods

resolveBlock :: r -> m b Source #

Instances

Instances details
Monad m => ResolvesBlocks r b (ExceptT e (ReaderT (ResolveBlock m r b) m)) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

resolveBlock :: r -> ExceptT e (ReaderT (ResolveBlock m r b) m) b Source #

Monad m => ResolvesBlocks r b (ReaderT (ResolveBlock m r b) m) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

resolveBlock :: r -> ReaderT (ResolveBlock m r b) m b Source #

class Monad m => ThrowsLedgerError l r m where Source #

Methods

throwLedgerError :: LedgerDB l r -> r -> LedgerErr l -> m a Source #

Instances

Instances details
Monad m => ThrowsLedgerError l r (ExceptT (AnnLedgerError l r) m) Source # 
Instance details

Defined in Ouroboros.Consensus.Storage.LedgerDB.InMemory

Methods

throwLedgerError :: LedgerDB l r -> r -> LedgerErr l -> ExceptT (AnnLedgerError l r) m a Source #

Updates

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.

ledgerDbPush :: forall m c l r b. (ApplyBlock l b, Monad m, c) => LedgerCfg l -> Ap m l r b c -> LedgerDB l r -> m (LedgerDB l r) Source #

ledgerDbSwitch Source #

Arguments

:: (ApplyBlock l b, Monad m, c) 
=> LedgerCfg l 
-> Word64

How many blocks to roll back

-> [Ap m l r b c]

New blocks to apply

-> LedgerDB l r 
-> m (Either ExceededRollback (LedgerDB l r)) 

Switch to a fork

Exports for the benefit of tests

Additional queries

ledgerDbChainLength :: LedgerDB l r -> Word64 Source #

Total length of the chain (in terms of number of blocks)

ledgerDbToList :: LedgerDB l r -> [(r, l)] Source #

References to blocks and corresponding ledger state (from old to new)

ledgerDbMaxRollback :: LedgerDB l r -> Word64 Source #

How many blocks can we currently roll back?

ledgerDbSnapshots :: forall l r. LedgerDB l r -> [(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.

ledgerDbIsSaturated :: LedgerDB l r -> Bool Source #

Have we seen at least k blocks?

ledgerDbCountToPrune :: LedgerDbParams -> Int -> Int Source #

Internal: count number of checkpoints to prune, given total number of checkpoints

This is exposed for the benefit of tests only.

ledgerDbPastSpec :: forall l r. Eq r => WithOrigin r -> LedgerDB l r -> Maybe l Source #

Get a past ledger state

\( O(n) \)

Straightforward implementation of ledgerDbPast using a linear search.

Can be used in tests to compare against ledgerDbPast.

Pure API

ledgerDbPush' :: ApplyBlock l b => LedgerCfg l -> b -> LedgerDB l b -> LedgerDB l b Source #

ledgerDbSwitch' :: forall l b. ApplyBlock l b => LedgerCfg l -> Word64 -> [b] -> LedgerDB l b -> Maybe (LedgerDB l b) Source #