Skip to main content

Block Construction

::: note

Work In Progress Section

:::

Message ordering

Currently, this document and EIP-3675 assumes that the message (or PoS event as per the EIP) delivery flow from the consensus to the execution layer maintains weak ordering.

For instance, the following message sequence is currently permitted:

@startuml
group engine_consensusValidated
Consensus->Execution: engine_consensusValidated ++ : B.payload.hash
end

group engine_executePayload
Consensus->Execution: engine_executePayload --++ : B.payload
Execution--> Consensus: engine_executePayloadResponse(B.payload.hash)
end

group engine_getPayload
Consensus->>Execution: engine_getPayload(parent: B.payload.hash) --++
end

group engine_forkChoiceUpdated
Consensus->>Execution: engine_forkChoiceUpdated(head: B.payload.hash) --++
end

group engine_getPayloadResponse
Execution--> Consensus: engine_getPayloadResponse(parent: B.payload.hash)
Consensus->Execution: engine_preparePayload(parent: B.payload.hash)
end
@enduml
@startuml
DB-->Observer: Last saved slot
Observer-->Observer: Calculate current slot
Observer-->Observer: Detect unprocessed slots
Relays-->Observer: Availability check
Relays-->Observer: Suggested payloads
Observer-->DB: Save results
@enduml

Currently, it is also not specified what to do if the engine_forkChoiceUpdated(head: B.payload.hash) has been delivered earlier than the payload it has a reference to. This document proposes to fall back to the consistency check with further recovery procedure in such a case. Which would mean that the order of some messages matter.

This section proposes to require maintaining of more strict ordering model for ingress messages pipeline of execution clients. Namely, require causal ordering to be maintained by consensus clients in the egress message pipeline and rely on the message ordering guarantee provided by TCP protocol (messages are delivered in the same order as they were sent within a TCP session, HTTP protocol doesn 't always use the same TCP session for different requests).

No additional requirement to the execution client is proposed by this section. It may not follow the order that is maintained by the ingress message pipeline while processing these messages. But, if an execution client would do this it would guarantee causal consistency in a normal operating mode. The latter means that no consistency checks or such a mechanism would be required between periods of outage. Also, depending on its architecture, an execution client might want to follow this order and might even require this ordering model to be followed by its ingress message pipeline.

It order to maintain causal ordering consensus clients will have to adhere the following set of rules:

  • Outgoing messages referencing the same execution block must be sent in the following sequence:
    Note over Consensus: Block B arrives
    Consensus->Execution: engine_executePayload(B.payload)
    Consensus->Execution: engine_consensusValidated(B.payload.hash)
    Execution-->Consensus: engine_executePayloadResponse(B.payload.hash)
    Consensus->Execution: engine_forkchoiceUpdated(head: B.payload.hash)
    Consensus->Execution: engine_preparePayload(parent: B.payload.hash)
    Consensus->Execution: engine_getPayload(parent: B.payload.hash)
    Note: Building a block on top of the head of not canonical chain may be allowed, then engine_forkchoiceUpdated(head: B.payload.hash) should be dropped out of this sequence.
  • The engine_forkchoiceUpdated message referencing a payload must be sent after the payload gets fully validated, specifically:
    Consensus->Execution: engine_executePayload(B.payload)
    Consensus->Execution: engine_consensusValidated(B.payload.hash)
    Execution-->Consensus: engine_executePayloadResponse(B.payload.hash)
    Consensus->Execution: engine_forkchoiceUpdated(head: B.payload.hash)
  • engine_executePayload and engine_consensusValidated calls must respect the parent ->child relation, specifically:
    Consensus->Execution: engine_executePayload(Parent.payload)
    Consensus->Execution: engine_consensusValidated(Parent.payload.hash)
    Execution-->Consensus: engine_executePayloadResponse(Parent.payload.hash)
    Consensus->Execution: engine_executePayload(Child.payload)
    Consensus->Execution: engine_consensusValidated(Child.payload.hash)
  • The engine_getPayload call must be made only if its parameter set matches the set of the most recent engine_preparePayload call, specifically:
    Consensus->Execution: engine_preparePayload(Set1)
    Consensus->Execution: engine_preparePayload(Set2)
    Consensus->Execution: engine_getPayload(Set2)
  • Maintain sequential order for engine_forkchoiceUpdated messages. It means that engine_forkchoiceUpdated messages must be sent respecting the order of their occurrence in the system, specifically:
    Note over Consensus: P becomes the head
    Consensus->Execution: engine_forkchoiceUpdated(head: P.payload.hash)
    Note over Consensus: P 'becomes the head
    Consensus->Execution: engine_forkchoiceUpdated(head: P '.payload.hash)
    Note over Consensus: C 'becomes the head
    Consensus->Execution: engine_forkchoiceUpdated(head: C '.payload.hash)
    Note over Consensus: C becomes the head
    Consensus->Execution: engine_forkchoiceUpdated(head: C.payload.hash)

Consensus software outage:

Note over Consensus: Outage
Consensus->Execution: engine_consensusStatus
Note over Execution: Catch ups with received data
Note left of Consensus: Normal functioning
Consensus->Execution: engine_executePayload
Consensus->Execution: ...

Execution software outage:

Note over Consensus:
Note over Execution: Outage
Consensus->Execution: engine_executePayload
Execution-->Consensus: engine_executionStatus
Consensus->Execution: engine_consensusStatus
Note over Execution: Catch ups with received data
Note left of Consensus: Block tree recovery
Consensus->Execution: engine_executePayload
Consensus->Execution: engine_consensusValidated
Consensus->Execution: ...
Consensus->Execution: engine_forkchoiceUpdated
Note left of Consensus: Normal functioning
Consensus->Execution: engine_executePayload
Consensus->Execution: ...