# What Is TxRouter? Transaction Propagation in the NEO P2P Network

> Discover TxRouter, the Akka.NET actor responsible for state-independent pre-verification and efficient transaction propagation across the NEO P2P network. Learn how it speeds up validation.

- Repository: [The Neo Project/neo](https://github.com/neo-project/neo)
- Tags: internals
- Published: 2026-03-08

---

**The TxRouter is a lightweight Akka.NET actor that performs state-independent pre-verification of incoming transactions before forwarding them to the Blockchain actor for full validation and network relay.**

In the `neo-project/neo` repository, the **TxRouter** (`Neo.Ledger.TransactionRouter`) serves as the first line of defense for transaction propagation across the peer-to-peer network. This specialized actor filters incoming transactions through lightweight checks before they reach the heavy-duty `Blockchain` actor, ensuring that only structurally valid transactions consume resources in the memory pool.

## How TxRouter Fits Into the Transaction Propagation Pipeline

### Entry Point from RemoteNode

When a remote peer sends a transaction inventory, the `RemoteNode` actor receives it through `OnInventory` in [`RemoteNode.ProtocolHandler.cs`](https://github.com/neo-project/neo/blob/main/RemoteNode.ProtocolHandler.cs). Before forwarding, it checks for duplicates or conflicts using `_system.ContainsTransaction` and `_system.ContainsConflictHash`. If the transaction passes these checks, it is sent to the TxRouter:

```csharp
_system.TxRouter.Tell(new TransactionRouter.Preverify(transaction, true));

```

*(see [[`RemoteNode.ProtocolHandler.cs`](https://github.com/neo-project/neo/blob/main/RemoteNode.ProtocolHandler.cs)](https://github.com/neo-project/neo/blob/master-n3/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs#L126-L130))*

### State-Independent Pre-Verification

The TxRouter receives the `Preverify` message in [`TransactionRouter.cs`](https://github.com/neo-project/neo/blob/main/TransactionRouter.cs) and immediately executes `VerifyStateIndependent`. This lightweight validation checks transaction structure, signatures, and basic rules without accessing the current blockchain state. The router then packages the result into a `PreverifyCompleted` message and forwards it to the `Blockchain` actor:

```csharp
protected override void OnReceive(object message)
{
    if (message is not Preverify preverify) return;
    var send = new PreverifyCompleted(
        preverify.Transaction,
        preverify.Relay,
        preverify.Transaction.VerifyStateIndependent(_system.Settings));
    _system.Blockchain.Tell(send, Sender);
}

```

*(see [[`TransactionRouter.cs`](https://github.com/neo-project/neo/blob/main/TransactionRouter.cs)](https://github.com/neo-project/neo/blob/master-n3/src/Neo/Ledger/TransactionRouter.cs#L26-L33))*

### Integration with the Blockchain Actor

Upon receiving `PreverifyCompleted`, the `Blockchain` actor in [`Blockchain.cs`](https://github.com/neo-project/neo/blob/main/Blockchain.cs) evaluates the verification result. If `VerifyResult.Succeed` is returned, the transaction proceeds to `OnInventory` for memory pool insertion and potential network relay. If pre-verification fails, the system immediately sends a relay failure result without wasting resources on full validation:

```csharp
private void OnPreverifyCompleted(TransactionRouter.PreverifyCompleted task)
{
    if (task.Result == VerifyResult.Succeed)
        OnInventory(task.Transaction, task.Relay);
    else
        SendRelayResult(task.Transaction, task.Result);
}

```

*(see [[`Blockchain.cs`](https://github.com/neo-project/neo/blob/main/Blockchain.cs)](https://github.com/neo-project/neo/blob/master-n3/src/Neo/Ledger/Blockchain.cs#L36-L44))*

## Direct RPC Entry Points and Internal Forwarding

The TxRouter also handles transactions submitted through RPC or other local sources. When the `Blockchain` actor receives a transaction directly (e.g., via `sendrawtransaction`), it checks for conflicts and forwards the transaction to the TxRouter using `Forward` instead of `Tell`, preserving the original sender reference:

```csharp
else
{
    if (_system.ContainsConflictHash(hash, tx.Signers.Select(s => s.Account)))
        SendRelayResult(tx, VerifyResult.HasConflicts);
    else
        _system.TxRouter.Forward(new TransactionRouter.Preverify(tx, true));
}

```

*(see [[`Blockchain.cs`](https://github.com/neo-project/neo/blob/main/Blockchain.cs)](https://github.com/neo-project/neo/blob/master-n3/src/Neo/Ledger/Blockchain.cs#L100-L107))*

## Why NEO Uses a Dedicated TxRouter Actor

### Parallel Processing with SmallestMailboxPool

The TxRouter is instantiated using a `SmallestMailboxPool` router configuration, creating one actor instance per CPU core. This design allows NEO to process multiple transaction pre-verifications in parallel, preventing network bottlenecks during high-throughput periods. The `SmallestMailboxPool` strategy routes new messages to the actor with the smallest mailbox, ensuring load balancing across cores:

```csharp
return Props.Create(() => new TransactionRouter(system))
            .WithRouter(new SmallestMailboxPool(Environment.ProcessorCount));

```

*(see [[`TransactionRouter.cs`](https://github.com/neo-project/neo/blob/main/TransactionRouter.cs)](https://github.com/neo-project/neo/blob/master-n3/src/Neo/Ledger/TransactionRouter.cs#L34-L38))*

### Separation of Concerns

By isolating state-independent verification in the TxRouter, the `Blockchain` actor remains focused on state-dependent validation, memory pool management, and block processing. This architectural boundary ensures that expensive blockchain state operations are never blocked by lightweight signature checks or format validations, improving overall node responsiveness.

## Summary

- The **TxRouter** (`TransactionRouter`) acts as a lightweight Akka.NET actor that performs **state-independent pre-verification** of transactions before they reach the `Blockchain` actor.
- It receives transactions from `RemoteNode` (P2P network) and directly from `Blockchain` (RPC/local sources), running `VerifyStateIndependent` to check signatures and structural validity.
- Valid transactions are forwarded to `Blockchain` as `PreverifyCompleted` messages for memory pool insertion and network relay; invalid transactions are rejected immediately.
- The actor uses a **`SmallestMailboxPool`** router with one instance per CPU core, enabling parallel pre-verification and preventing bottlenecks in the P2P transaction propagation pipeline.

## Frequently Asked Questions

### What is the difference between TxRouter and the Blockchain actor?

The **TxRouter** performs lightweight, state-independent verification (signature checks, format validation) using only the transaction data itself. The **Blockchain** actor handles state-dependent validation (checking balances, nonces against the current ledger state), manages the memory pool, and coordinates block processing. This separation allows the TxRouter to filter out invalid transactions before they consume resources in the Blockchain actor.

### How does TxRouter improve transaction throughput?

TxRouter improves throughput through **parallelism** and **load balancing**. It is configured as a `SmallestMailboxPool` with one actor instance per CPU core, allowing multiple transactions to be pre-verified simultaneously. By offloading state-independent checks from the main Blockchain actor, it prevents the validation pipeline from stalling during high-volume network traffic.

### What happens if a transaction fails pre-verification in TxRouter?

If a transaction fails the `VerifyStateIndependent` check in the TxRouter, it is **immediately rejected** without being forwarded to the Blockchain actor or entering the memory pool. The TxRouter sends a `PreverifyCompleted` message with a failure result (e.g., `VerifyResult.InvalidSignature`), and the system sends a relay failure response to the originating peer or RPC client.

### Is TxRouter used for all transaction types in NEO?

Yes, the TxRouter handles **all transaction types** that enter the node through the P2P network or RPC interfaces. Whether the transaction is a standard transfer, smart contract deployment, or complex invocation, it must first pass through the TxRouter's state-independent verification before the Blockchain actor processes it for state-dependent validation and inclusion in the memory pool.