Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Synopsis
- data family ConsensusConfig p ∷ Type
- class (Show (ChainDepState p), Show (ValidationErr p), Show (SelectView p), Show (LedgerView p), Eq (ChainDepState p), Eq (ValidationErr p), ChainOrder (SelectView p), NoThunks (ConsensusConfig p), NoThunks (ChainDepState p), NoThunks (ValidationErr p), NoThunks (SelectView p), Typeable p) ⇒ ConsensusProtocol p where
- type ChainDepState p ∷ Type
- type IsLeader p ∷ Type
- type CanBeLeader p ∷ Type
- type SelectView p ∷ Type
- type LedgerView p ∷ Type
- type ValidationErr p ∷ Type
- type ValidateView p ∷ Type
- checkIsLeader ∷ HasCallStack ⇒ ConsensusConfig p → CanBeLeader p → SlotNo → Ticked (ChainDepState p) → Maybe (IsLeader p)
- tickChainDepState ∷ ConsensusConfig p → LedgerView p → SlotNo → ChainDepState p → Ticked (ChainDepState p)
- updateChainDepState ∷ HasCallStack ⇒ ConsensusConfig p → ValidateView p → SlotNo → Ticked (ChainDepState p) → Except (ValidationErr p) (ChainDepState p)
- reupdateChainDepState ∷ HasCallStack ⇒ ConsensusConfig p → ValidateView p → SlotNo → Ticked (ChainDepState p) → ChainDepState p
- protocolSecurityParam ∷ ConsensusConfig p → SecurityParam
- class Ord sv ⇒ ChainOrder sv where
- type ChainOrderConfig sv ∷ Type
- preferCandidate ∷ ChainOrderConfig sv → sv → sv → Bool
- newtype SimpleChainOrder sv = SimpleChainOrder sv
- class TranslateProto protoFrom protoTo where
- translateLedgerView ∷ Proxy (protoFrom, protoTo) → LedgerView protoFrom → LedgerView protoTo
- translateChainDepState ∷ Proxy (protoFrom, protoTo) → ChainDepState protoFrom → ChainDepState protoTo
- newtype SecurityParam = SecurityParam {}
Abstract definition of the Ouroboros protocol
data family ConsensusConfig p ∷ Type Source #
Static configuration required to run the consensus protocol
Every method in the ConsensusProtocol
class takes the consensus
configuration as a parameter, so having this as a data family rather than a
type family resolves most ambiguity.
Defined out of the class so that protocols can define this type without having to define the entire protocol at the same time (or indeed in the same module).
Instances
class (Show (ChainDepState p), Show (ValidationErr p), Show (SelectView p), Show (LedgerView p), Eq (ChainDepState p), Eq (ValidationErr p), ChainOrder (SelectView p), NoThunks (ConsensusConfig p), NoThunks (ChainDepState p), NoThunks (ValidationErr p), NoThunks (SelectView p), Typeable p) ⇒ ConsensusProtocol p where Source #
The (open) universe of Ouroboros protocols
This class encodes the part that is independent from any particular block representation.
type ChainDepState p ∷ Type Source #
Protocol-specific state
NOTE: This chain is blockchain dependent, i.e., updated when new blocks come in (more precisely, new headers), and subject to rollback.
type IsLeader p ∷ Type Source #
Evidence that a node is the leader
type CanBeLeader p ∷ Type Source #
Evidence that we can be a leader
type SelectView p ∷ Type Source #
View on a header required for chain selection
Chain selection is implemented by the chain database, which takes care of
two things independent of a choice of consensus protocol: we never switch
to chains that fork off more than k
blocks ago, and we never adopt an
invalid chain. The actual comparison of chains however depends on the chain
selection protocol. We define chain selection in terms of a select view
on the headers at the tips of those chains: chain A is strictly preferred
over chain B whenever A's select view is preferred over B's select view
according to the ChainOrder
instance.
type SelectView p = BlockNo
type LedgerView p ∷ Type Source #
Projection of the ledger state the Ouroboros protocol needs access to
The LedgerView
is a summary of the state of the ledger that the consensus
algorithm requires to do its job. Under certain circumstances the consensus
algorithm may require the LedgerView
for slots in the past (before the
current tip of the chain) or in the (near) future (beyond the tip of the
current chain, without having seen those future blocks yet).
This puts limitations on what the LedgerView
can be. For example, it
cannot be the "current stake distribution", since it is of course
impossible to compute the current stake distibution for a slot in the
future. This means that for a consensus algorithm that requires the
stake distribution such as Praos, the LedgerView
for a particular slot
must be the "stake distribution for the purpose of leader selection".
This "relevant" stake distribution can be computed for slots in the
(near) future because it is based on historical stake, not current.
A somewhat unfortunate consequence of this is that some decisions that ought to live in the consensus layer (such as the decision precisely which historical stake to sample to determine the relevant stake distribution) instead live in the ledger layer. It is difficult to disentangle this, because the ledger may indeed depend on those sampling decisions (for example, reward calculations must be based on that same stake distribution).
There are also some advantages to moving these sorts of decisions to the ledger layer. It means that the consensus algorithm can continue to function without modifications if we decide that the stake distribution for leader selection should be based on something else instead (for example, for some bespoke version of the blockchain we may wish to use a committee instead of a decentralized blockchain). Having sampling decisions in the ledger layer rather than the consensus layer means that these decisions can be made without modifying the consensus algorithm.
Note that for the specific case of Praos, whilst the ledger layer provides the relevant stake distribution, the precise leader election must still live in the consensus layer since that depends on the computation (and sampling) of entropy, which is done consensus side, not ledger side (the reward calculation does not depend on this).
type ValidationErr p ∷ Type Source #
Validation errors
type ValidateView p ∷ Type Source #
View on a header required to validate it
checkIsLeader ∷ HasCallStack ⇒ ConsensusConfig p → CanBeLeader p → SlotNo → Ticked (ChainDepState p) → Maybe (IsLeader p) Source #
Check if a node is the leader
tickChainDepState ∷ ConsensusConfig p → LedgerView p → SlotNo → ChainDepState p → Ticked (ChainDepState p) Source #
Tick the ChainDepState
We pass the LedgerView
to tickChainDepState
. Functions that take a
ticked ChainDepState
are not separately passed a ledger view; protocols
that require it, can include it in their ticked ChainDepState
type.
updateChainDepState ∷ HasCallStack ⇒ ConsensusConfig p → ValidateView p → SlotNo → Ticked (ChainDepState p) → Except (ValidationErr p) (ChainDepState p) Source #
Apply a header
reupdateChainDepState ∷ HasCallStack ⇒ ConsensusConfig p → ValidateView p → SlotNo → Ticked (ChainDepState p) → ChainDepState p Source #
Re-apply a header to the same ChainDepState
we have been able to
successfully apply to before.
Since a header can only be applied to a single, specific,
ChainDepState
, if we apply a previously applied header again it will be
applied in the very same ChainDepState
, and therefore can't possibly
fail.
It is worth noting that since we already know that the header is valid
w.r.t. the provided ChainDepState
, no validation checks should be
performed.
protocolSecurityParam ∷ ConsensusConfig p → SecurityParam Source #
We require that protocols support a k
security parameter
Instances
Chain order
class Ord sv ⇒ ChainOrder sv where Source #
The chain order of some type; in the Consensus layer, this will always be
the SelectView
of some ConsensusProtocol
.
See preferCandidate
for the primary documentation.
Additionally, we require a total order on this type, such that eg different
candidate chains that are preferred over our current selection can be sorted
for prioritization. For example, this is used in ChainSel during initial
chain selection or when blocks arrive out of order (not the case when the
node is caught up), or in the BlockFetch decision logic. Future work could
include also recording/storing arrival information and using that instead
of/in addition to the Ord
instance.
type ChainOrderConfig sv ∷ Type Source #
∷ ChainOrderConfig sv | |
→ sv | Tip of our chain |
→ sv | Tip of the candidate |
→ Bool |
Compare a candidate chain to our own.
This method defines when a candidate chain is strictly preferable to our current chain. If both chains are equally preferable, the Ouroboros class of consensus protocols always sticks with the current chain.
Requirements
Write ours ⊏ cand
for
for brevity.preferCandidate
cfg ours cand
- Consistency with
Ord
- When
ours ⊏ cand
, thenours < cand
.This means that
cand
can only be preferred overours
whencand
is greater thanours
according to theOrd
instance.However, this is not necessarily a sufficient condition; a concrete implementation may decide to not have
ours ⊏ cand
despiteours < cand
for some pairsours, can
. However, it is recommended to think about this carefully and rather useSimpleChainOrder
if possible, which definesours ⊏ cand
asours < cand
, as it simplifies reasoning about the chain ordering.However, forgoing
SimpleChainOrder
can enable more sophisticated tiebreaking rules that eg exhibit desirable incentive behavior. - Chain extension precedence
a
must contain the underlying block number, and use this as the primary way of comparing chains.Suppose that we have a function
blockNo :: sv -> Natural
. Then for alla, b
withblockNo a < blockNo b
we must havea ⊏ b
.Intuitively, this means that only the logic for breaking ties between chains with equal block number is customizable via this class.
Instances
newtype SimpleChainOrder sv Source #
A DerivingVia
helper to implement preferCandidate
in terms of the Ord
instance.
Instances
Translation
class TranslateProto protoFrom protoTo where Source #
Translate across protocols
translateLedgerView ∷ Proxy (protoFrom, protoTo) → LedgerView protoFrom → LedgerView protoTo Source #
Translate the ledger view.
translateChainDepState ∷ Proxy (protoFrom, protoTo) → ChainDepState protoFrom → ChainDepState protoTo Source #
Instances
TranslateProto singleProto singleProto Source # | Degenerate instance - we may always translate from a protocol to itself. |
Defined in Ouroboros.Consensus.Protocol.Abstract translateLedgerView ∷ Proxy (singleProto, singleProto) → LedgerView singleProto → LedgerView singleProto Source # translateChainDepState ∷ Proxy (singleProto, singleProto) → ChainDepState singleProto → ChainDepState singleProto Source # |
Convenience re-exports
newtype SecurityParam Source #
Protocol security parameter
We interpret this as the number of rollbacks we support.
i.e., k == 0: we can't roll back at all k == 1: we can roll back at most one block, etc
NOTE: This talks about the number of blocks we can roll back, not the number of slots.