Transaction Flow: User to Finality

⏱️ Duration: ~30 min 📊 Difficulty: Level 1 🎯 Hyperscale-rs Specific

Learning Objectives

By the end of this module, you will:

Why This Diagram?

Hyperscale-rs is a consensus layer, not a full blockchain stack. This diagram shows the end-to-end path of a transaction from the user to finality, and which parts Hyperscale touches versus which are outside (e.g. wallet, Radix Engine semantics, network client). Hover over each step to see which crates implement it.

Level 1 placement: You’ve done Blockchain and Consensus in generic web3 modules; this module gives a single-shard Hyperscale map before systems theory. Deep dives: after this map, optional phase modules zoom into step groups (start with Phase 1: Submit → Mempool). Then: Distributed Systems, State Machines, OSS first PR, Overview, Crate Groups.

Where BFT comes in: Steps 1–6 get the tx into the system (user, network, node, cross-shard determination, mempool, and for cross-shard txs, travel to involved shards). BFT consensus runs from step 7 (proposer selection) through step 11 (block commit) per shard. Steps 12–14 are execution, then (for cross-shard) coordination & composition, then finality.

Single-shard vs multi-shard (canonical split): Steps 1–6 are the same. From step 7 onward, BFT runs per shard (each shard has its own proposer, block, votes, QC, commit). Single-shard: After step 11 (block commit), step 12 (execution) runs immediately—no provisioning. Multi-shard: After step 11, the execution crate registers the tx with ProvisionCoordinator and waits for ProvisioningComplete (quorum of StateProvisions from each required shard); then it runs the five-phase protocol (State Provisioning → Provision Verification → Deterministic Execution → Vote Aggregation → Finalization). There is no 2PC coordinator in hyperscale-rs; atomicity is provision-based. See Phase 4: Cross-Shard Transactions and Phase 3: Execution & Waves for detail.

End-to-End Transaction Flow

Hyperscale-rs (consensus layer) Outside Hyperscale (wallet, engine, network)
1. User signs transaction
Wallet creates and signs a transaction (e.g. transfer, smart contract call).

Crates

Not in Hyperscale — wallet / client application.

2. Transaction submitted to network
RPC or gateway sends the signed tx to a node (or broadcast).

Crates

Network client / RPC — outside. production receives on the node side.

3. Node receives transaction
Runner turns incoming bytes into Events and feeds the node.

Crates

  • production — I/O, turns network into events
  • node — NodeStateMachine receives events
4. Cross-shard determination
The tx is analyzed for which NodeIDs (components, resources, packages, accounts) it reads or writes. If those NodeIDs belong to more than one shard, the tx is classified as a cross-shard transaction.

Crates

  • node — routing, shard mapping
  • core — Event/Action types

Shard assignment of NodeIDs is defined by the protocol / Radix Engine; consensus uses it to decide single- vs cross-shard.

5. Mempool (per shard)
Single-shard: tx goes into that shard's mempool. Cross-shard: the receiving node enqueues the tx in its own shard’s mempool (if the tx touches that shard). For other involved shards, the tx is sent in step 6 and nodes there enqueue it in their mempools — so the tx ends up in the mempool of every involved shard. Deep dive Phase 1 (steps 1–5, production path).

Crates

  • mempool — transaction pool
  • node — composes mempool
  • core — Event/Action types
6. (Cross-shard) Tx travels to each involved shard
For cross-shard txs, the receiving node (or the routing layer) sends the tx (or sub-transactions) to the nodes of every other involved shard. Those nodes enqueue it in their shard’s mempool. Each shard then runs steps 7–12 for its part. Cross-shard atomicity is provision-based (StateProvision, ProvisionCoordinator, step 13)—there is no 2PC coordinator or prepare/commit/abort. Deep dive Phase 4 (after Phase 1 gossip path).

Crates

  • provisions — centralized provision coordination; drives cross-shard flow
  • production — cross-shard messaging (libp2p Gossipsub on shard-scoped topics)
  • node — composes provisions, coordination state

In Hyperscale-rs, the node sends the tx to other shards via the production network layer: libp2p Gossipsub with shard-scoped topics (e.g. hyperscale/{msg_type}/shard-{id}/1.0.0). RPC is only for client→node submission.

Cycles: live protocol uses execution’s ConflictDetector (crates/execution/src/conflict.rs); simulator post-run analysis uses crates/simulator/src/livelock.rs.

7. Proposer selection (per shard, per round)
BFT starts here. Each shard runs its own BFT instance with its own view/round. The proposer (block leader) is chosen deterministically from the shard's validator set (e.g. round-robin by validator identity or view number modulo validator count). Deep dive Phase 2 (steps 7–11).

Crates

  • shard — view, leader election
  • core — traits, time
  • types — block, validator set
8. Block proposal
Proposer builds block (header + txs from mempool), broadcasts header; validators receive it. Phase 2try_propose / BuildProposal.

Crates

  • shard — proposal logic
  • types — Block, BlockHeader
  • node — routes protocol events, timers, try_event_driven_proposal
9. Validators vote
Validators in this shard's BFT instance validate the block (e.g. check it extends from the parent QC, payload and hashes are valid, and it obeys consensus rules) and, if valid, sign a vote. 2f+1 votes are required for a quorum (BFT fault model: n = 3f+1 nodes per shard). Phase 2 — BLS votes & VoteSet.

Crates

  • shard — block validation logic and voting; collects votes
  • types — Block, Vote, signatures
10. Quorum certificate (QC) formed
How a QC is formed: (i) Proposer for H built and broadcast the block header (step 8). (ii) Validators validated and voted; votes are broadcast to the shard (step 9). (iii) When any validator has 2f+1 valid votes, it requests QC build; that node’s latest_qc is set to the new QC. (iv) The QC is not sent as a separate message—the next proposer has it by forming it from votes or from a received block header. (v) The next proposer builds block H+1 with parent_qc = QC(H) and broadcasts H+1; everyone then sees QC(H) in H+1’s header. Phase 2 — QC & two-chain lead-in.

Crates & code

  • shard — vote collection, QC build request, latest_qc, block build with parent_qc
  • typesBlockHeader.parent_qc in block.rs, QuorumCertificate
  • coreAction::PersistAndBroadcastVote, Action::VerifyAndBuildQuorumCertificate in action.rs

Locations: ShardCoordinator in shard/src/coordinator.rs (QC bookkeeping, try_propose, commit pipeline). QC aggregation in action_handlers.rs + vote_set.rs (build_qc). Line numbers drift—search for the symbol names.

11. Block commit
Who: Every validator node in the shard (not only the proposer). Once the commit rule is satisfied (e.g. two-chain: this block and the next have QCs), each node commits. Commit mechanics: (1) accept the block as final, (2) append it to the local chain, (3) trigger execution (run the transactions in the block), (4) trigger persistence (write to storage). All honest nodes do this in sync with the agreed order. Phase 2 — commit & mempool transitions.

Crates

  • node — CommitBlock action, composition
  • shard — commit rule
  • core — Action::CommitBlock

“Node” = any validator running the NodeStateMachine in this shard; the proposer is one of them. All commit the same block in the same order.

12. Execution
Transactions in the block are executed (per shard). Hyperscale runs the execution state machine; semantics (e.g. Radix Engine) may be external. Deep dive Phase 3 (single-shard waves).

Crates

  • execution — execution state machine; provision-based cross-shard (no 2PC coordinator)
  • engine — Radix Engine integration for smart contract execution
  • node — composes execution

Execution semantics (Radix Engine) are in engine crate / vendor; BFT only orders and coordinates.

13. (Cross-shard) Coordination & composition
For cross-shard txs, atomic composability is achieved by a provision-based protocol (no 2PC). After a shard commits its block, validators produce StateProvisions (signed proofs) and send them to other shards. ProvisionCoordinator on each node tracks quorum of provisions from each required shard; when it has provisions from every required shard it emits ProvisioningComplete. Execution then runs in a fixed protocol order (e.g. by shard ID); vote aggregation and TransactionCertificate follow. There is no prepare/commit/abort—only StateProvision → ProvisionCoordinator checklist → execution and certificate aggregation. Single-shard txs skip this. Deep dive Phase 4.

Crates

  • provisions — centralized provision coordination for cross-shard txs
  • execution — transaction execution with provision-based cross-shard coordination (no 2PC)
  • node — composes provisions, execution, core
  • core — Event/Action for coordination

See module “Cross-Shard Transactions” for provision coordination and the five-phase protocol.

14. Finality & persistence
BFT gives one-round finality (no reorg after QC). State/storage may be in-node or external. Cross-shard finality ties to Phase 4; persistence ops tie to E2E harness (prod).

Crates

  • shard — finality rule
  • node — state, persistence

Tip: Hover over a step to see which crates implement it. Popup closes when you move the cursor away.

Block anatomy — bird's-eye map

How the 14-step tx flow lines up with phase modules and the interactive BlockHeader + body cards (pistachio green = fields newly highlighted at that card). Full cards live in phase deep-dives — this table is the summary only.

Clarifying the flow (multi-shard and proposer)

A few common points to keep straight:

  • Proposer is per shard, per round. The node that receives the tx (e.g. via RPC) belongs to some shard, but that does not make it the proposer. Proposer is chosen deterministically per shard (e.g. round-robin by view). So for shard A, “the proposer for this round” is one validator in A; for shard B, it’s one validator in B. They are different nodes. The receiving node just ingests the tx (steps 3–6); the tx lands in mempool(s) of every involved shard. The proposer pulls from its shard’s mempool when ShardCoordinator::try_propose runs after new mempool/QC/provision activity — it doesn’t “receive the tx” specially.
  • Who enqueues in which mempool? The node that receives the tx (e.g. RPC node) belongs to one shard. It can enqueue the tx in its own shard’s mempool (if the tx touches that shard). It cannot directly enqueue into another shard’s mempool — that shard’s mempool lives on that shard’s nodes. So for cross-shard: the receiving node enqueues in its shard’s mempool (step 5) and sends the tx (or sub-tx) to the other involved shards (step 6). Nodes in those shards receive it and enqueue it in their mempools. So the tx ends up in the mempools of every involved shard, but “enqueue in mempools of every involved shard” is done by the receiving node for its shard and by the other shards’ nodes when they receive the tx.
  • Tx does not “broadcast until it lands on the proposer.” Once the tx is in the mempools (as above), each shard’s proposer pulls from that shard’s mempool on the next successful try_propose and builds a block. The proposer broadcasts the block (header) to validators in that shard only, not to other shards.
  • Proposer sends a block to its shard, not “the block” to all shards. The proposer for shard S builds one block (header with parent_qc = QC for previous block in S’s chain, plus txs from S’s mempool). It broadcasts that block (or header; full block is assembled via gossip) to validators in shard S only. So: one block per shard, broadcast inside that shard. Other shards have their own proposers and their own blocks at the same “logical” time.
  • Voting and execution order. Validators in that shard vote on the block (BFT: do we agree on this block?). That yields a QC for that shard’s block. Then the block is committed (step 11). After commit, execution runs (step 12): the transactions in the block are run (e.g. via Radix Engine). So: BFT agrees on block → commit → then execute. There is no “each shard votes on validity and reports to the proposer” in the sense of one global proposer; each shard votes on its own block and gets its own QC.
  • Cross-shard: no single “proposer finalizes with all shards’ QCs.” Each shard has its own chain and its own QC. For a cross-shard tx, the tx (or sub-tx) is in each involved shard’s mempool; each shard may include it in its block; each shard runs BFT (propose → vote → QC → commit) and then execution. Atomicity across shards is achieved by the provision-based protocol (step 13): StateProvisions from source shards, ProvisionCoordinator checklist (quorum per required shard), then deterministic execution and certificate aggregation in a fixed order. There is no 2PC—no prepare/commit/abort coordinator. There is no single block that “includes the votes (QC) of each shard” — each shard’s block has its own QC in the next block’s header (the normal two-chain rule per shard).
  • What is the coordinator? In hyperscale-rs there is no 2PC coordinator; cross-shard flow uses ProvisionCoordinator only (provision-based protocol). For the full picture (protocol order, five phases, conflict detection), see Phase 4: Cross-Shard Transactions and Phase 3: Execution & Waves.

For how cross-shard atomicity works (provision-based protocol: StateProvision → ProvisionCoordinator → execution), how order is fixed (by ShardId, not manifest line order), and concepts (shards, proposer, NodeID, finality), see Phase 4 and Phase 3.

Crate groupings (code reading order)

The codebase is grouped by transaction-flow progression. Read the groups in order (1 → 6); use the quizzes in the next module to check understanding.

Group Crates One-liner
1. First contactproduction, node, mempool, types, core, messagesHow Hyperscale receives a tx at the RPC and gets it into the right shards’ mempools.
2. Sharding and routingtypes, core, nodeWho does what once a tx is decomposed into NodeIds and each shard is responsible for a slice of state.
3. Proposing and building blocksshard, mempool, types, coreHow one validator becomes the proposer and assembles the next block from the mempool.
4. Voting and committingshard, types, coreHow validators agree on a block and when it is finally committed (votes and QCs).
5. Execution after commitexecution, engine, node, types, coreWho runs transactions after commit and how single-shard vs cross-shard paths diverge.
6. Cross-shard: provisions & conflictsprovisions, execution (ConflictDetector), types, core; simulator diagnosticsHow state moves between shards and how dependency cycles are resolved deterministically.

Use the crate-groups table above as your workspace map; phase deep-dives and harness modules come next on the course index.

Messaging & transports inventory

There is no standalone course module titled “Messaging and Transports.” Messaging and notifications are covered across this page (end-to-end path), State machines & event-driven architecture (how Event / Action and channels compose), the libp2p modules in the Hyperscale basic/intermediate/advanced tracks, and the file links in the tables below. Treat these tables as a reading map: concrete struct names, lock types (Arc<Mutex<HashSet<…>>> vs alternatives), and exact eviction rules can shift between commits — when in doubt, set breakpoints on the linked paths.

How to read the columns. Message source / destination are logical actors (threads, coordinators, peers). Transport is how bits move (RPC, gossip, in-process call). Lifecycle storage is where the payload or derived state usually sits until the next phase. Pruning / flushing / drainage is what makes that storage go away or become irrelevant. The last column, Handlers · registration · done, answers: (a) which functions / traits / closures participate, (b) when they are wired (skip the row if it is always the same boring answer), and (c) how the callee signals completion back into the pinned ShardLoop / state machine.

Source alignment. Handler tables below match network_handlers.rs and host.rs in the hyperscale-rs repo (data-file links open the cited crate paths).

Suggested pacing. Each subsection is sized for roughly 8–25 minutes. The full inventory is about 65–95 minutes if you read the registry plus all four flow chunks in order; skip what you already know.

0. Typed network inbound registry (~8–12 min)

Every typed inbound path registered on the Network trait is wired in network_handlers.rs and invoked from NodeHost::register_inbound_handlersregister_request_handler, register_gossip_handlers, register_notification_handlers. Registration happens once per node before the main loop processes traffic — on both genesis and resume paths (see host.rs / shard/lifecycle.rs); it is not repeated each round.

The Network trait (crates/network/src/traits.rs) names the dispatch hooks: GossipHandler::on_message, NotificationHandler::on_notification, RequestHandler::handle_request. Outbound Network::request(..., on_response) uses a per-call FnOnce(Result<R::Response, RequestError>) -> ResponseVerdict (not listed row-by-row here); that callback is typically registered at fetch time and completes by pushing a NodeInput onto the same event_sender channel as gossip.

Registration API Wire type Trait dispatch When registered How “done” is signaled
register_gossip_handler::<TransactionGossip>TransactionGossipGossipHandler::on_messageOnce in register_inbound_handlers (before loop)Returns GossipVerdict::Accept / Reject to the network stack; closure also send(NodeInput::TransactionGossipReceived) per tx.
register_gossip_handler::<CommittedBlockHeaderGossip>CommittedBlockHeaderGossipGossipHandler::on_messageSameGossipVerdict; may send(NodeInput::CommittedBlockGossipReceived) after filters.
register_notification_handler::<BlockVoteNotification>BlockVoteNotificationNotificationHandler::on_notificationSameNo return value; send(NodeInput::Protocol(BlockVoteReceived …)).
register_notification_handler::<BlockHeaderNotification>BlockHeaderNotificationNotificationHandler::on_notificationSameVerify then send(ProtocolEvent::BlockHeaderReceived …) wrapped in NodeInput::Protocol; drop on bad sig.
register_notification_handler::<ProvisionsNotification>ProvisionsNotificationNotificationHandler::on_notificationSameVerify shard + sig; send(ProtocolEvent::ProvisionsReceived …) or return early.
register_notification_handler::<ExecutionVotesNotification>ExecutionVotesNotificationNotificationHandler::on_notificationSamePer-vote send(ProtocolEvent::ExecutionVoteReceived …).
register_notification_handler::<ExecutionCertificatesNotification>ExecutionCertificatesNotificationNotificationHandler::on_notificationSamesend(ProtocolEvent::ExecutionCertificatesReceived …).
register_request_handler::<GetBlockRequest>GetBlockRequestRequestHandler::handle_requestSameReturns GetBlockResponse synchronously to the requester (may run on blocking pool per adapter).
register_request_handler::<GetTransactionsRequest>GetTransactionsRequestRequestHandler::handle_requestSameReturns GetTransactionsResponse.
register_request_handler::<GetProvisionsRequest>GetProvisionsRequestRequestHandler::handle_requestSameReturns GetProvisionResponse; producer path uses mutex + Condvar for single-flight dedup.
register_request_handler::<GetLocalProvisionsRequest>GetLocalProvisionsRequestRequestHandler::handle_requestSameReturns GetLocalProvisionsResponse.
register_request_handler::<GetFinalizedWavesRequest>GetFinalizedWavesRequestRequestHandler::handle_requestSameReturns GetFinalizedWavesResponse.
register_request_handler::<GetExecutionCertsRequest>GetExecutionCertsRequestRequestHandler::handle_requestSameReturns GetExecutionCertsResponse.
register_request_handler::<GetRemoteHeadersRequest>GetRemoteHeadersRequestRequestHandler::handle_requestSameReturns remote-header sync payload.

1. Edge & ShardLoop (~12–18 min)

How a transaction first enters the process: user RPC vs peer gossip. Both converge on ShardLoop before anything synchronous runs in the state machine.

Message source Message destination Transport Lifecycle storage (type · location) Pruning / flushing / drainage Handlers · registration · done
User / wallet (signed transaction) Validator RPC / gateway (production) HTTP / JSON-RPC (or similar); TLS terminates outside the pure state machine Ephemeral deserialization buffers on the RPC worker thread; decoded NotarizedTransaction (or equivalent) until handoff to the node I/O path RPC response returned to client; request-scoped allocations dropped. Failed validation returns an error without entering consensus queues.
  • Symbols: Framework route / handler in crates/production (not a Network::register_* hook).
  • Registered: When the RPC server is started (node bring-up); independent of register_inbound_handlers.
  • Done: Completes to the client with an HTTP response; any enqueue to ShardLoop is an internal follow-up in the production crate.
RPC or gateway worker ShardLoop (pinned / dedicated runner thread) In-process queue: NodeInput (or equivalent) from the production runner — not libp2p Bounded in-memory queue between “network / RPC world” and the thread that drives the state machine; backpressure policy is deployment-specific Drained as ShardLoop runs step; on shutdown, remaining items are dropped with teardown. Under overload, policy may drop or reject before enqueue (inspect runner).
  • Symbols: Production code sends NodeInput::SubmitTransaction (see ShardLoop match arms); channel pair with event_sender / receiver.
  • Registered: Channel endpoints created when the runner builds ShardLoop, before run().
  • Done: send on the crossbeam channel; consumer marks work complete when that input is processed in step and any follow-on actions for that turn are dispatched.
Remote validator (same shard) ShardLoop libp2p gossipsub over QUIC (validator mesh, separate from wallet HTTP) → network_handlersNodeInput::TransactionGossipReceived Adapter receive path + validation staging before a ProtocolEvent is emitted; dedupe / “already seen” structures often live near gossip ingress (pattern: set or map keyed by message id / hash — exact type varies) Duplicates rejected early (never reach mempool). After acceptance, gossip-derived state may be short-lived; some paths tombstone or remember ids briefly for idempotency — verify in tx_validation.rs.
  • Symbols: register_gossip_handler::<TransactionGossip> closure (GossipHandler::on_message); then handle_gossip_received_tx_for_validationqueue_validationflush_validation_batch spawns DispatchPool::TxValidation closure (tx_validation.rs).
  • Registered: Gossip closure: table §0 (once before loop). Validation pool: bound when ShardLoop / dispatch is constructed.
  • Done: Gossip path returns GossipVerdict::Accept to the network layer. Validation worker send(NodeInput::TransactionValidated { … }) or TransactionValidationsFailed; handle_transaction_validated then feed_event(ProtocolEvent::TransactionValidated …).

2. Node interior & mempool (~12–18 min)

The synchronous core: one event in, actions out. Validated transactions land in RAM pools that are separate from BFT vote maps and from long-term disk.

Message source Message destination Transport Lifecycle storage (type · location) Pruning / flushing / drainage Handlers · registration · done
Decoded network / RPC input NodeStateMachine Synchronous handle(event) -> Vec<Action> after ShardLoop dequeues (see StateMachine trait) No durable queue inside the pure state machine — only stack-local work and returned actions Not applicable per event: actions are returned immediately to the runner for side effects.
  • Symbols: StateMachine::handle / NodeStateMachine::handle (not a libp2p callback).
  • Registered: Trait impl bound when the state machine struct is built — not at register_inbound_handlers time.
  • Done: Synchronous return of Vec<Action>; ShardLoop::process_actions runs immediately in the caller thread (no channel round-trip for the pure step).
Validation pipeline (post-signature / manifest checks) MempoolCoordinator In-process: ProtocolEvent::TransactionValidated path via state/participation/transactions.rs Per-shard pool structures in mempool coordinator — typically maps / sets / priority structures keyed by transaction id and account sequence rules Removed when the transaction is included in a committed block, replaced under policy (e.g. same sender nonce), or evicted when pools exceed size / fee thresholds.
  • Symbols: MempoolCoordinator::on_transaction_gossip (and related admission helpers from the TransactionValidated routing in transactions.rs).
  • Registered: Coordinator owned by NodeStateMachine at construction — not a network register_* call.
  • Done: Admission runs synchronously inside handle; further work is expressed as new Actions returned from the state machine, not a thread callback.
Mempool (ordered candidates) ShardCoordinator (try_propose, proposal build) Direct calls from node composition into BFT; not a second network hop Proposal construction buffers (pending txs pulled for the next block header / body) Superseded when a different proposal wins the round, or when the view advances without committing that candidate.
  • Symbols: ShardCoordinator::try_propose, on_proposal_built, on_qc_formed, … (see coordinator.rs); node glue in state/participation/proposal.rs / state/participation/shard.rs.
  • Registered: BFT struct is composed into the node state at init; methods run when events/timers schedule them — same for genesis and resume.
  • Done: Returns Vec<Action> inline; heavy crypto / build work is delegated separately (next section).

3. BFT mesh, commit, and persistence (~15–22 min)

Shard-scoped gossip for headers and votes, then durable commit. This chunk is where “messages” look most like classical consensus traffic.

Message source Message destination Transport Lifecycle storage (type · location) Pruning / flushing / drainage Handlers · registration · done
Current round proposer All validators on the shard Gossip notifications: block header path (see messages::notification) Encode buffers on send; peers hold BFT “pending proposal” / header caches until QC or timeout Replaced by higher-round headers or cleared after QC commits the height; view-change paths discard stale pending work.
  • Symbols: Sender side: ShardCoordinator::on_proposal_built + delegated actions (Action::BroadcastBlockHeader, …) handled by handle_shard_action in shard/actions.rs. Receivers: register_notification_handler::<BlockHeaderNotification> (§0).
  • Registered: Inbound notification closure: once (§0). Delegated spawn: each time matching Actions are emitted.
  • Done: Delegated work uses ActionContext::notifyevent_sender.send(NodeInput::…); libp2p send itself is async, but the app callback finishes when the send enqueues the next input.
Each validator after verifying header Proposer + peers Gossip: BlockVote (and related notification variants in messages) Vote bookkeeping in BFT — e.g. vote_keeper.rs, pending.rs, vote_set.rs for QC formation Pruned when QC is built for the height, or when round / view timers cause cleanup of stale vote maps.
  • Symbols: register_notification_handler::<BlockVoteNotification>NodeInput::Protocol(BlockVoteReceived …); state routes to ShardCoordinator::on_block_vote.
  • Registered: Notification table §0 (same timing for all rows there — not repeated below).
  • Done: Notification closure completes synchronously after send; vote aggregation “finishes” when the later handle pass returns the next Actions (e.g. toward QC).
BFT commit path Local persistence + optional broadcast follow-ups Action::Persist*, CommitBlock, and network actions emitted by the runner Committed blocks and certificates on disk (blockstore / DB — exact backend is node deployment); in-memory mirrors for hot path Archival / compaction is operator policy, not mempool-style eviction. Unlike RAM pools, on-disk data is retained until configured pruning.
  • Symbols: ShardLoop::process_action for inline effects; dispatch_delegated_action + handle_shard_action / crypto verify actions for heavy paths; feed_event from commit pipeline (e.g. ProtocolEvent::BlockPersisted in step/protocol_event.rs).
  • Registered: Delegated pool wiring at ShardLoop construction; per-action spawn is dynamic.
  • Done: Inline arms finish before process_action returns. Delegated arms call notify to enqueue NodeInput for a later step; block-commit batching uses feed_event / flush per module docs.

4. Execution, cross-shard, and operational paths (~15–22 min)

What happens after commit, how shards coordinate without a 2PC coordinator, and auxiliary transports (timers, simulation, catch-up sync).

Message source Message destination Transport Lifecycle storage (type · location) Pruning / flushing / drainage Handlers · registration · done
Committed block / receipts ExecutionCoordinator Internal protocol events after commit; then calls into engine for Radix semantics Execution wave state, receipt tiers (receipt model), coordinator tables until certificates finalize Drained when the wave completes and transaction / receipt certificates are settled for the affected txs; conflict resolution may drop loser txs per ConflictDetector rules.
  • Symbols: handle_execution_action (shard/actions.rsdispatch_delegated_action); execution crate on_* routines driven by ProtocolEvents after commit.
  • Registered: Delegated pool at ShardLoop build; work is scheduled when ExecuteTransactions / verify-cert Actions appear.
  • Done: Worker calls the same notify closure → NodeInput on event_sender; often Action::Continuation(…) / follow-up ProtocolEvent pattern — see execution action handlers.
Shard A (provisions / receipts) Peer shards + provision composition in node Cross-shard messages over gossip (shard-scoped topics) + in-node provisions coordination — not a classic 2PC coordinator ProvisionCoordinator-style in-memory maps: quorum of StateProvisions per required shard until ProvisioningComplete Drained after deterministic execution in fixed shard order and certificate aggregation, or along deterministic abort / conflict paths (see Cross-Shard module).
  • Symbols: register_notification_handler::<ProvisionsNotification> (§0); handle_provisions_action for delegated provision fetches; node routes ProtocolEvent::ProvisionsReceived into the provision coordinator.
  • Registered: Notification row §0; provision action handler registered via the same dispatch / ShardLoop wiring as other delegated actions.
  • Done: Inbound: synchronous send after verify. Coordinator progress: synchronous state-machine steps plus delegated notify for async verify/fetch legs.
Wall clock / simulated time Node + BFT timers Timer driver → timers.rsProtocolEvent Pending timer registrations keyed by round / phase (view-change, cleanup, proposal retry) One-shot timers fire then unregister; many are cancelled on view advance so stale timeouts cannot commit old rounds.
  • Symbols: State machine emits Action::SetTimer / CancelTimer; ShardLoop buffers TimerOp in pending_timer_ops (mod.rs); runner installs OS / logical timers.
  • Registered: Runner-specific: production binds wall-clock callbacks that enqueue timer NodeInputs; sim injects timer events — both are after loop start, not part of §0.
  • Done: Firing is modeled as a normal NodeInput / ProtocolEvent into step; cancellation clears the op without a callback.
Simulator workload driver ShardLoop / fake network Synthetic events from simulator / simulation instead of real sockets Scheduled event lists and in-memory “network” queues Emptied per simulation step or at scenario end; use livelock analyzer post-run for stuck txs.
  • Symbols: Sim harness schedules NodeInput (e.g. schedule_initial_event); SyncDispatch runs delegated closures inline so ordering is deterministic.
  • Registered: Per-scenario setup in sim runner — not network §0.
  • Done: Harness observes empty queues / step output; no libp2p verdict.
Sync / fetch protocol (catch-up) Peer nodes Request/response over libp2p (see shard/protocol) — distinct from mempool gossip Chunk buffers, block body staging, integrity checks before commit Temporary buffers freed after successful import; failed sync attempts may retry with backoff (runner-specific).
  • Symbols: Network::request(..., on_response: Box<dyn FnOnce(Result<…>) -> ResponseVerdict + Send>) per fetch (traits.rs); server side uses §0 request handlers.
  • Registered: A new on_response closure each outbound fetch (not the one-time §0 table).
  • Done: Callback runs on a network thread and usually sends a NodeInput carrying fetch results; returns ResponseVerdict for peer health scoring.

Why this is not a single “messaging crate” story. User ingress, gossip, shard notifications, execution sidecars, and persistence each use different transports and lifetimes. Gossip payloads live under hyperscale_types::network; node registers handlers in process/network_handlers.rs; mempool and shard own the longest-lived RAM pools until commit or eviction.

Practical next steps: run the code and debug

Use these steps to run Hyperscale and follow a transaction with a debugger. They assume you have the repo cloned and cargo build works.

  1. Read Event and Action first. The flow is “event in → state machine → actions out; runner performs actions and feeds back events.” Skim the core event and action modules (see Suggested crates / files to study) so you know what to break on.
  2. Run a node or the simulator. Follow the repo README to run a single node or the sim (e.g. cargo run for the production runner or sim binary). Submit one transaction and note its hash (from logs or RPC).
  3. Follow one tx with a debugger. In your IDE, set breakpoints on: SubmitTransaction / TransactionGossipReceived (ingress + validation) and ProtocolEvent::TransactionValidated (mempool), then BFT commit paths, then execution wave/certificate handling. Step through to see which crates handle each step.
  4. Use the messaging inventory tables. The production runner is large. Use the tables above — start with the full register_* registry, then the edge → mempool → BFT → execution chunks — to jump to “first contact” (RPC handler, submit path, gossip) and “actions to network” (e.g. BroadcastToShard handling) instead of reading the production crate top to bottom.
  5. When things go wrong: tx stuck in Pending → check mempool and gossip (did the tx reach all involved shards?). Block not committing → BFT and QC (round/timeout, vote collection). Cross-shard tx stuck after Executed → certificates and inclusion in a later block (provisions, certificate aggregation).

Quiz: Transaction Flow (big picture)

Answer based on the diagram and concepts above. Pass threshold: 70%.

Suggested crates / files to study

Use alongside the diagram popups above. Paths are relative to the hyperscale-rs repo root.

Focus Path
Event / Action enums crates/core/src/protocol_event.rs, crates/core/src/action.rs
Submit + gossip ingress crates/node/src/shard/mod.rsSubmitTransaction, validation pipeline
Node state machine crates/node/src/state/mod.rs, crates/node/src/state/participation/transactions.rsProtocolEvent::TransactionValidated; state/participation/shard.rs for commit/QC dispatch
Production RPC / runner crates/production — submit path, runner