# Neo Caching Mechanisms: How RelayCache, HeaderCache, and ReflectionCache Boost Node Performance

> Discover how Neo's caching mechanisms RelayCache, HeaderCache, and ReflectionCache boost performance by reducing network broadcasts, disk I/O, and reflection calls.

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

---

**Neo uses three specialized in-memory caches—RelayCache, HeaderCache, and ReflectionCache—to eliminate redundant network broadcasts, minimize disk I/O during block verification, and avoid expensive reflection calls during message serialization.**

The `neo-project/neo` repository implements a high-performance blockchain node architecture that relies on strategic caching to maintain throughput. These Neo caching mechanisms store hot data in fast memory, reducing the computational overhead associated with peer-to-peer networking, ledger validation, and object instantiation.

## Understanding Neo Caching Mechanisms

Blockchain nodes face constant pressure to validate data, synchronize with peers, and serialize network messages. Without caching, every operation would require disk access or expensive computational reflection. Neo addresses these bottlenecks through three purpose-built caches that operate at different layers of the stack: network relaying, ledger storage, and message serialization.

## RelayCache: Preventing Duplicate Network Broadcasts

The **RelayCache** prevents the node from repeatedly broadcasting the same inventory objects—such as transaction or block hashes—to peers that have already received them.

### Implementation Details

`RelayCache` is implemented as a FIFO cache in [`src/Neo/IO/Caching/RelayCache.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/IO/Caching/RelayCache.cs). It stores `IInventory` objects keyed by their `UInt256` hash with a default capacity of 100 entries. The cache is instantiated inside `NeoSystem` at line 96-99:

```csharp
internal RelayCache RelayCache { get; } = new(100);

```

When processing network payloads, the protocol handler in [`src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs) checks the cache at lines 273-276 before re-broadcasting:

```csharp
if (_system.RelayCache.TryGet(hash, out IInventory inventory))
{
    // Already relayed – skip re‑broadcast
}

```

### Performance Impact

By filtering duplicate inventory announcements, **RelayCache** cuts network bandwidth consumption and eliminates redundant CPU cycles spent on validation and message construction for data the peer already possesses.

## HeaderCache: Accelerating Block Verification

The **HeaderCache** maintains a bounded collection of recent block headers in memory, enabling rapid verification of incoming blocks without querying the persistent store.

### Thread-Safe Design

Implemented in [`src/Neo/Ledger/HeaderCache.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Ledger/HeaderCache.cs), this cache uses an `IndexedQueue<Header>` protected by a `ReaderWriterLockSlim` to ensure thread safety during concurrent access. The cache enforces a maximum capacity of 10,000 headers as defined at lines 27-30:

```csharp
public const int MaxHeaders = 10_000;

```

It provides O(1) indexed access via the `this[uint index]` operator, along with `Count`, `Last`, `Add`, and `TryRemoveFirst` operations.

### Integration with Blockchain Sync

`HeaderCache` is instantiated in `NeoSystem` at lines 94-98:

```csharp
public HeaderCache HeaderCache { get; } = [];

```

The cache is heavily utilized during blockchain synchronization in [`src/Neo/Ledger/Blockchain.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Ledger/Blockchain.cs) (lines 226-304), where headers are validated and queued before full block data arrives. This allows the node to pre-validate proof-of-work and chain continuity without waiting for disk I/O.

```csharp
// Fast header lookup during sync
if (system.HeaderCache.TryRemoveFirst(out Header? header))
{
    // Process header without disk access
}

```

## ReflectionCache: Optimizing Message Serialization

The **ReflectionCache** eliminates the performance penalty of runtime reflection when instantiating network message payloads and transaction attributes.

### Enum-to-Type Mapping

Located in [`src/Neo/IO/Caching/ReflectionCache.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/IO/Caching/ReflectionCache.cs), this static generic cache maps enum values to concrete .NET `Type` objects. During static initialization, the cache scans fields for the `[ReflectionCache]` attribute and populates an internal dictionary at lines 26-38:

```csharp
static ReflectionCache()
{
    foreach (var field in typeof(T).GetFields())
    {
        var attribute = field.GetCustomAttribute<ReflectionCacheAttribute>();
        if (attribute is null) continue;
        var key = (T)field.GetValue(null)!;
        s_dictionary.Add(key, attribute.Type);
    }
}

```

### Usage in Network Layer

The cache provides factory methods `CreateInstance(T key)` and `CreateSerializable(T key, byte[] data)` that convert dictionary lookups into instantiated objects. This pattern is used in [`src/Neo/Network/P2P/Message.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/Network/P2P/Message.cs) at lines 119-121 for deserializing network commands:

```csharp
var payload = (ISerializable)ReflectionCache<MessageCommand>
    .CreateSerializable(command, data);

```

By caching the reflection metadata once per enum type, **ReflectionCache** transforms expensive `Activator.CreateInstance` calls into cheap dictionary lookups, significantly accelerating message deserialization and payload construction.

## Summary

- **RelayCache** stores the last 100 inventory hashes to prevent redundant network broadcasts, reducing bandwidth and CPU usage.
- **HeaderCache** maintains up to 10,000 block headers in memory with O(1) access, eliminating disk I/O during chain synchronization.
- **ReflectionCache** maps enum values to concrete types via static dictionaries, removing runtime reflection overhead from message serialization.

## Frequently Asked Questions

### What is the maximum capacity of Neo's RelayCache?

The `RelayCache` is initialized with a fixed capacity of 100 entries as defined in [`NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/NeoSystem.cs) (`new RelayCache(100)`). This FIFO cache stores recent inventory objects keyed by their `UInt256` hash, ensuring the node only tracks the most recent broadcasts without consuming excessive memory.

### How does HeaderCache prevent disk I/O during block synchronization?

`HeaderCache` maintains up to 10,000 block headers in an `IndexedQueue<Header>` protected by a `ReaderWriterLockSlim`. By keeping headers in memory with O(1) indexed access, the node can validate chain continuity and proof-of-work using `HeaderCache[index]` or `TryRemoveFirst()` without querying the persistent store, keeping the sync pipeline busy while waiting for full block data.

### Why does ReflectionCache use static generic dictionaries?

`ReflectionCache<T>` uses a static dictionary populated once per enum type during static construction. This design caches the mapping between enum values (decorated with `[ReflectionCache]`) and their concrete .NET `Type` objects, eliminating the need for expensive reflection calls like `GetCustomAttributes` or `Activator.CreateInstance` during hot paths such as network message deserialization.

### Where are these caching mechanisms instantiated in the Neo codebase?

All three caches are instantiated in [`src/Neo/NeoSystem.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/NeoSystem.cs). `RelayCache` is initialized as `new RelayCache(100)` at line 96, while `HeaderCache` is instantiated as `public HeaderCache HeaderCache { get; } = [];` at line 94. `ReflectionCache` is a static generic class defined in [`src/Neo/IO/Caching/ReflectionCache.cs`](https://github.com/neo-project/neo/blob/main/src/Neo/IO/Caching/ReflectionCache.cs) and does not require instance creation, being accessed directly via `ReflectionCache<T>.CreateInstance()` or `CreateSerializable()`.