Control flow between Supervisor and Managed node
Table of Contents
This section is based on the control flow between managed
node and supervisor
, described
here.
Whether the node and supervisor use a pubsub
pattern or pulling events over HTTP is up to the implementation detail.
Both cases should be handled because op-node
and op-supervisor
can be using different client implementations.
In both the case, we use event
based signaling of new information. Ideally, this should be done using bi-directional
RPC using web sockets.
Authentication
Supervisor initiates the connection to the node in order to manage it. As supervisor does the dial in, for our context, it is the client and the node is the server. For the web socket authentication, only the initial request is authenticated and a live socket is opened. No re-authentication is needed during the lifetime of this socket.
The authentication is performed using JWT
. The construction of jwt is similar to the one
used in Engine API. The path of
the file containing the jwt secret should be provided to the supervisor instance. If no input is provided, a new
jwt should be generated and stored in hex encoded format.
Node ->
Supervisor
Events that a supervisor should subscribe to, originating from the node, handled by the supervisor. For the used types, refer this section.
Every event sent from the node is of type ManagedEvent
whose fields are populated with the events that occurred. All
non-null events are sent at once. The other fields are omitted.
ManagedEvent {
Reset,
UnsafeBlock,
DerivationUpdate,
DerivationOriginUpdate,
ExhaustL1,
ReplaceBlock
}
Each field item is an event of the type as described below:
Reset
Reset: string
This is emitted when the node has completed resetting its chain, after it received interop_reset
event from
supervisor.
UnsafeBlock
UnsafeBlock: BlockRef //L2's BlockRef
New L2 unsafe block was processed, updating local-unsafe head.
DerivationUpdate
DerivationUpdate: DerivedBlockRefPair {
Source: BlockRef //L1
Derived: BlockRef //Last L2 BlockRef
}
Signals that an L2 block is considered local-safe.
DerivationOriginUpdate
DerivationOriginUpdate: BlockRef
Signals that an L2 block is now local-safe because of the given L1 traversal. This would be accompanied with
DerivationUpdate
.
ExhaustL1
ExhaustL1: DerivedBlockRefPair {
Source: BlockRef //Last L1
Derived: BlockRef //Last L2 BlockRef
}
Emitted when no more L1 Blocks are available. Ready to take new L1 blocks from supervisor.
ReplaceBlock
ReplaceBlock: BlockReplacement
Emitted when a block gets replaced for any reason.
Supervisor ->
Node
Messages that a node should watch for, originating from supervisor, handled by node. This also includes control signals that the supervisor can ask the node to perform. For the used types, refer this section.
Note: Headings represent the actual name of the methods over RPC, payload is the serialized version of the given type.
-> indicates return
Control Signals
RPC calls that are relevant to managing the node via supervisor. These are directly called by the supervisor.
interop_pullEvent
payload: none -> One of the event from node events (previous section).
When websocket is not available, supervisor can use this method to get the next event from node.
interop_anchorPoint (Soon to be deprecated)
payload: none -> DerivedBlockRefPair {
Source: L1 BlockRef that rollup starts after (no derived transaction)
Derived: L2 BlockRef that rollup starts from (no txn, pre-configuration state)
}
Returns the genesis block ref for L1 and L2 that the current node used as anchor point. This method will soon be removed in favor of fetching the information from a supervisor specific rollup config. (Once a spec is created about this PR.)
interop_invalidateBlock
payload: BlockSeal //L2's Block
Based on some dependency or L1 changes, supervisor can instruct the L2 to invalidate a specific block.
(Suggestion: BlockSeal can be replaced with Hash, as only that is being used in op-node.)
interop_provideL1
payload: BlockRef //L1 Block
Supervisor sends the next L1 block to the node. Ideally sent after the node emits exhausted-l1
.
interop_reset
payload: (lUnsafe, xUnsafe, lSafe, xSafe, finalized: BlockID)
Forces a reset to a specific local-unsafe/local-safe/finalized starting point only if the blocks did exist. Resets may override local-unsafe, to reset the very end of the chain. Resets may override local-safe, since post-interop we need the local-safe block derivation to continue.
DB
RPC calls that a node should watch for, originating from supervisor that is called on DB updates for relevant block safety info for a given chain and block.
interop_updateCrossSafe
payload: (derived: BlockID, derivedFrom: BlockID)
Signal that a block can be promoted to cross-safe.
interop_updateCrossUnsafe
payload: BlockID
Signal that a block can be promoted to cross-unsafe.
interop_updateFinalized
payload: BlockID
Signal that a block can be marked as finalized.
Sync Methods
RPC methods that are relevant for syncing the supervisor. These are directly called by the supervisor for fetching L2 data.
interop_fetchReceipts
payload: Hash -> Receipts //L2 block hash
Fetches all transaction receipts in a given L2 block.
interop_l2BlockRefByTimestamp
payload: uint64 -> BlockRef
Fetches L2 BlockRef of the block that occurred at given timestamp
interop_blockRefByNumber
payload: uint64 -> BlockRef
Fetches the BlockRef from a given L2 block number
interop_chainID
payload: none -> uint256
Returns chainID of the L2
interop_outputV0AtTimestamp
payload: uint64 -> OutputV0
Returns the state root, storage root and block hash for a given timestamp
interop_pendingOutputV0AtTimestamp
payload: uint64 -> OutputV0
Returns the optimistic output of the invalidated block from replacement
Note: All events should return relevant error(s) in case of unsuccessful calls.
Types
Hash: 0x prefixed, hex encoded, fixed-length string representing 32 bytes
BlockID {
Hash: Hash
Number: uint64
}
BlockSeal {
Hash: Hash
Number: uint64
Timestamp: uint64
}
BlockRef {
Hash: Hash
Number: uint64
ParentHash: Hash
Time: uint64
}
L2BlockRef {
Hash: Hash
Number: uint64
ParentHash: Hash
Time: uint64
L1Origin: BlockID
SequenceNumber: uint64 //distance to first block of epoch
}
DerivedBlockRefPair {
Source: BlockRef
Derived: BlockRef
}
BlockReplacement {
Replacement: BlockRef
Invalidated: Hash
}
Receipts -> []Receipt
Receipt -> op-geth/core/types/receipt
OutputV0 {
StateRoot: Hash
MessagePasserStorageRoot: Hash
BlockHash: Hash
}