Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Synopsis
- class (Show (TentativeHeaderState blk), NoThunks (TentativeHeaderState blk), Show (TentativeHeaderView blk)) ⇒ BlockSupportsDiffusionPipelining blk where
- type TentativeHeaderState blk ∷ Type
- type TentativeHeaderView blk ∷ Type
- initialTentativeHeaderState ∷ Proxy blk → TentativeHeaderState blk
- tentativeHeaderView ∷ BlockConfig blk → Header blk → TentativeHeaderView blk
- applyTentativeHeaderView ∷ Proxy blk → TentativeHeaderView blk → TentativeHeaderState blk → Maybe (TentativeHeaderState blk)
- updateTentativeHeaderState ∷ ∀ blk. BlockSupportsDiffusionPipelining blk ⇒ BlockConfig blk → Header blk → TentativeHeaderState blk → Maybe (TentativeHeaderState blk)
- newtype DisableDiffusionPipelining blk = DisableDiffusionPipelining blk
- newtype SelectViewDiffusionPipelining blk = SelectViewDiffusionPipelining blk
- data SelectViewTentativeState proto
- = LastInvalidSelectView !(SelectView proto)
- | NoLastInvalidSelectView
- data family BlockConfig blk ∷ Type
- data family Header blk ∷ Type
Documentation
class (Show (TentativeHeaderState blk), NoThunks (TentativeHeaderState blk), Show (TentativeHeaderView blk)) ⇒ BlockSupportsDiffusionPipelining blk where Source #
Block functionality required to support __Block Diffusion Pipelining via Delayed Validation__ (DPvDV).
High-level context
With DPvDV, a node is, under certain conditions, already announcing a new block to its downstream peers before it has fully validated the block body. Concretely, the node maintains a tentative header that, if present, extends the current selection, and is announced via the ChainSync servers to downstream peers.
Ideally, the body turns out to be valid, in which case the tentative header
is set to Nothing
, and the selection is updated to now include the header
at its tip.
If the body corresponding to the tentative header turns out to be invalid (we call such a header a trap header), the tentative header is cleared, and the ChainSync servers send a rollback instruction. In this case, the network wasted work in diffusing, storing and validating this block. If abused, this could cause an unbounded amount of work for honest nodes. Hence, we need to enforce that our upstream nodes adhere to an appropriate criterion related to trap headers, and so must also restrict ourselves accordingly such that downstream nodes do not disconnect from us.
Semantics
This type class allows to define a block-specific criterion determining whether a header that might turn out to be a trap header is allowed to be set as the tentative header.
This is used in two places:
- The ChainSel logic. We make sure that we only set the tentative header if this criterion is fulfilled.
- The BlockFetch clients, in combination with the ChainSel validation logic. For every upstream BlockFetch peer, we make sure that the invalid blocks this peer sent adhere to the pipelining criterion.
Concretely, the abstract Consensus layer maintains TentativeHeaderState
s
(one in ChainSel, and one for each (BlockFetch) upstream peer). Suppose that
hdr
either might turn out or is already known to be a trap header. Then
applyTentativeHeaderView
(Proxy
@blk) thv st
(where thv =
) will returntentativeHeaderView
bcfg hdr
Nothing
ifhdr
does not satisfy the pipelining criterion.- In ChainSel, this means that
hdr
should not be pipelined, as it would violate the criterion if it turns out to be a trap header. - In the BlockFetch punishment logic, this means that we disconnect from the peer that sent the corresponding invalid block.
- In ChainSel, this means that
ifJust
st'hdr
does satisfy the pipelining criterion. If thehdr
is (in the BlockFetch punishment logic) or turns out to be (in ChainSel) a trap header, theTentativeHeaderState
should be updated to the returnedst'
.
Requirements
Safety
The criterion is sufficiently strict such that an adversary can not induce an unbounded amount of work for honest nodes.
Consistent validity under subsequences
Suppose that over some period of time, an honest node advertised the headers
hdrs :: [Header blk]
as its trap tentative headers. A downstream honest
node might only observe a subsequence of this list (there's no guarantee that
every ChainSync server sends every selected tip), but must still consider our
behavior as valid.
Hence, for every subsequence thvs'
of thvs =
, we need to havetentativeHeaderView
bcfg
<$>
hdrs
isJust
hdrs'Valid
for all st ::
andTentativeHeaderState
blk
hdrsValid =foldlM
(flip
$applyTentativeHeaderView
p) st thvs hdrs'Valid =foldlM
(flip
$applyTentativeHeaderView
p) st thvs'
where
and isJust
hdrsValidp ::
.Proxy
blk
Efficiently enforcible
The TentativeHeaderState
must have bounded size, and
applyTentativeHeaderView
must be efficient and objective (different nodes
must agree on its result for the same header and state).
As a historical example for establishing objectivity, see the removal of the isSelfIssued tiebreaker in the chain order.
Usefulness despite adversarial activity
It must not be possible for an adversary to easily manipulate the
TentativeHeaderState
in such a way that almost no headers can be pipelined
anymore. It is acceptable if DPvDV is less effective in scenarios involving
an adversary with a very large amount of resources (like stake).
type TentativeHeaderState blk ∷ Type Source #
State that is maintained to judge whether a header can be pipelined. It can be thought of as a summary of all past trap tentative headers.
type TentativeHeaderView blk ∷ Type Source #
View on a header required for updating the TentativeHeaderState
.
initialTentativeHeaderState ∷ Proxy blk → TentativeHeaderState blk Source #
The initial TentativeHeaderState
. This is used as the initial value on
node startup, as well as by the HFC instance for new eras.
tentativeHeaderView ∷ BlockConfig blk → Header blk → TentativeHeaderView blk Source #
See TentativeHeaderView
.
applyTentativeHeaderView Source #
∷ Proxy blk | |
→ TentativeHeaderView blk | Extracted using |
→ TentativeHeaderState blk | The most recent |
→ Maybe (TentativeHeaderState blk) | The new |
Apply a TentativeHeaderView
to the TentativeHeaderState
. This returns
to indicate that the underlying header can be pipelined, and
that the Just
stTentativeHeaderState
must be updated to st
if the header
turns/turned out to be a trap header (ie the corresponding block body is
invalid).
Also see updateTentativeHeaderState
.
Instances
updateTentativeHeaderState ∷ ∀ blk. BlockSupportsDiffusionPipelining blk ⇒ BlockConfig blk → Header blk → TentativeHeaderState blk → Maybe (TentativeHeaderState blk) Source #
Composition of tentativeHeaderView
and applyTentativeHeaderView
.
DerivingVia
helpers
DisableDiffusionPipelining
newtype DisableDiffusionPipelining blk Source #
A DerivingVia
helper to implement BlockSupportsDiffusionPipelining
for
blocks where no header should ever be pipelined.
deriving via DisableDiffusionPipelining MyBlock instance BlockSupportsDiffusionPipelining MyBlock
Instances
SelectViewDiffusionPipelining
newtype SelectViewDiffusionPipelining blk Source #
A DerivingVia
helper to implement BlockSupportsDiffusionPipelining
for
blocks where a header should be pipelined iff it has a better SelectView
than the last tentative trap header.
deriving via DisableDiffusionPipelining MyBlock instance BlockSupportsProtocol blk => BlockSupportsDiffusionPipelining MyBlock
This requires that the SelectView
is totally ordered, in particular that
the order is transitive.
For example, if
, this means that a header can be
pipelined if it has a larger block number than the last tentative trap
header. So if someone diffused a trap header for a particular block height,
no other block can be pipelined for that block height. This would limit the
Usefulness despite adversarial activity if an attacker diffuses a trap
header (and later also a valid block) every time they are elected.SelectView
~ BlockNo
Instances
data SelectViewTentativeState proto Source #
TentativeHeaderState
(SelectViewDiffusionPipelining
blk) ~SelectViewTentativeState
(BlockProtocol
blk)
Instances
Data family instances
data family BlockConfig blk ∷ Type Source #
Static configuration required to work with this type of blocks
Instances
data family Header blk ∷ Type Source #