-
Notifications
You must be signed in to change notification settings - Fork 99
Description
Context
We currently store state in a builder-wide, shared State struct. All actively processed accounts are shared:
/// Tracks all network accounts with inflight state.
///
/// This is network account deltas, network notes and their nullifiers.
accounts: HashMap<NetworkAccountPrefix, AccountState>,The AccountState instances hold account updates and inflight notes:
/// Tracks the state of a network account and its notes.
pub struct AccountState {
/// The committed account state, if any.
///
/// Its possible this is `None` if the account creation transaction is still inflight.
committed: Option<Account>,
/// Inflight account updates in chronological order.
inflight: VecDeque<Account>,
/// Unconsumed notes of this account.
available_notes: HashMap<Nullifier, InflightNetworkNote>,
/// Notes which have been consumed by transactions that are still inflight.
nullified_notes: HashMap<Nullifier, InflightNetworkNote>,
}We have the option to split up network account workloads because network accounts are independent of each other. The main benefit of this is to allow for specialized per-account logic. But we expect to also have wins in terms of performance, complexity, and further functionality as we continue to develop the NTX builder.
High Level Design
Core Components
1. Account Actor (AccountActor)
Each network account prefix gets a dedicated long-running async task that:
- Maintains isolated account state (inflight notes, nullifiers)
- Processes transactions sequentially (no internal concurrency)
- Handles any account-specific configuration and logic
- Captures panics in order to inform coordinator of impending shutdown
struct AccountActor {
account_prefix: NetworkAccountPrefix,
state: AccountState,
coordinator_rx: mpsc::UnboundedReceiver<CoordinatorMessage>,
coordinator_tx: mpsc::UnboundedSender<ActorMessage>,
ntx_context: NtxContext,
rate_limiter: Arc<Semaphore>,
config: AccountConfig,
}
pub struct ActorHandle {
account_prefix: NetworkAccountPrefix,
coordinator_tx: mpsc::UnboundedSender<CoordinatorMessage>,
join_handle: tokio::task::JoinHandle<()>,
}2. Central Coordinator (NtxCoordinator or just existing NetworkTransactionBuilder)
A single coordinator task that:
- Subscribes to mempool events from the block producer
- Routes events to appropriate account actors via channels
- Manages actor lifecycle (spawn, monitor, restart on failure)
- Implements global rate limiting
- Maintains a registry of active account actors
- Handles account discovery and cleanup
This could either be embedded directly into the current NetworkTransactionBuilder::serve_new() loop, or made as a separate struct that is integrated a bit more loosely.
// Within NetworkTransactionBuilder::serve_new()
let mut actor_registry = HashMap::<NetworkAccountPrefix, ActorHandle>::new();
let rate_limiter = Arc::new(Semaphore::new(MAX_IN_PROGRESS_TXS));
loop {
tokio::select! {
event = mempool_events.try_next() => {
// Route to appropriate actors or spawn new ones
},
actor_msg = actor_message_rx.recv() => {
// Handle actor completion/failure messages
},
_tick = interval.tick() => {
// Trigger periodic processing across all actors
},
}
}3. Coordinator-Actor Communication
- Mempool Events: Coordinator fans out events to relevant actors via bounded channels
- Control Messages: Coordinator sends lifecycle and configuration messages to actors
- Status Reporting: Actors report health and completion status back to coordinator
- Global Coordination: Semaphore-based permits for global rate limiting
enum CoordinatorMessage {
MempoolEvent(MempoolEvent),
ConfigUpdate(AccountConfig),
Shutdown,
}
enum ActorMessage {
TransactionCompleted {
account: NetworkAccountPrefix,
tx_id: TransactionId,
result: Result<()>, NtxError>
},
ActorFailed {
account: NetworkAccountPrefix,
error: NtxError
},
ActorReady {
account: NetworkAccountPrefix
},
}Key Flows
Actor Lifecycle Management
Actor management is handled by the NtxCoordinator.
New Transaction → New Network Account → Spawn Actor
Actor Crash → Capture and Send Message to Coordinator → Respawn Actor
Account Deleted → Shutdown Actor
Event Flow
Typical transaction processing would occur as follows:
Block Producer → Coordinator → Account Actor → Coordinator
The second actor message would indicate success or failure.