Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Network Transaction Builder Component

The network transaction builder (NTB) is responsible for driving the state of network accounts.

What is a network account

Network accounts are a special type of fully public account which contains no authentication and whose state can therefore be updated by anyone (in theory). Such accounts are required when publicly mutable state is needed.

The issue with publicly mutable state is that transactions against an account must be sequential and require the previous account commitment in order to create the transaction proof. This conflicts with Miden's client side proving and concurrency model since users would race each other to submit transactions against such an account.

Instead the solution is to have the network be responsible for driving the account state forward, and users can interact with the account using notes. Notes don't require a specific ordering and can be created concurrently without worrying about conflicts. We call these network notes and they always target a specific network account.

A network transaction is a transaction which consumes and applies a set of network notes to a network account. There is nothing special about the transaction itself - it can only be identified by the fact that it updates the state of a network account.

Limitations

At present, we artificially limit this such that only this component may create transactions against network accounts. This is enforced at the RPC layer by disallowing network transactions entirely in that component. The NTB skirts around this by submitting its transactions directly to the block-producer.

This limitation is there to prevent complicating the NTBs implementation while the protocol and definitions of network accounts, notes and transactions mature.

Implementation

The NTB uses an actor-per-account model managed by a central Coordinator. On startup the coordinator syncs all known network accounts and their unconsumed notes from the store. It then monitors the mempool for events (via a gRPC event stream from the block-producer) which would impact network account state.

For each network account, the coordinator spawns a dedicated AccountActor. Each actor runs in its own async task and is responsible for creating transactions that consume network notes targeting its account. On startup, each actor waits until its account has been committed to the chain before producing any transactions. This means newly created network accounts will idle until their creation transaction is included in a block. Once the committed state is available, the actor reads its state from the database and re-evaluates whenever notified by the coordinator.

Actors that have been idle (no available notes to consume) for longer than the idle timeout will be deactivated. The idle timeout is configurable via the --ntx-builder.idle-timeout CLI argument (default: 5 minutes).

Deactivated actors are re-spawned when new notes targeting their account are detected by the coordinator (via the send_targeted path).

If an actor repeatedly crashes (shuts down due to a database error), its crash count is tracked by the coordinator. Once the count reaches the configurable threshold, the account is deactivated and no new actor will be spawned for it. This prevents resource exhaustion from a persistently failing account. The threshold is configurable via the --ntx-builder.max-account-crashes CLI argument (default: 10).

The block-producer remains blissfully unaware of network transactions. From its perspective a network transaction is simply the same as any other.

gRPC Server

The NTX exposes an internal gRPC server for querying its state. The RPC component proxies public requests to this server. In bundled mode the server is started automatically on a random port and wired to the RPC; in distributed mode operators must pass the NTB's address to the RPC via --ntx-builder.url (or MIDEN_NODE_NTX_BUILDER_URL).

Currently the only endpoint is GetNetworkNoteStatus(note_id) which returns the lifecycle status of a network note (pending, processed, or discarded), along with the latest execution error, attempt count, and block number of the last attempt. This is useful for debugging notes that fail to be consumed.