As Nano has evolved and we have learned how developers and exchanges use the network and RPCs, we started thinking about ways that we could improve the network in terms of security and throughput. One of the keys to Nano’s success has been eliminating waste to make the network operate as efficiently as possible.

The Nano network currently has four different types of blocks (open, change, send, and receive), each having slightly different shapes to them without any real need. By introducing Universal Blocks, these four block types will be consolidated into one.

This protocol upgrade increases the efficiency of the network, helps improve security and simplifies code needed to construct a block for developers and exchange. In this post we will detail the benefits of Universal Blocks as well as the implementation plan.

An example of a UTX block

Signature Checking Performance Improvement

Currently block signatures are checked while running the main ledger insert process. This leads to a few performance drawbacks:

These signatures are processed serially, which means database locks are held open longer than needed during the signature checking process.

We do not know what account to verify the signature against simply by looking at the block. I/O operations must be performed to find the associated account from the block before we can find the account number to verify against.

An extra database index is required to map head block hashes to their associated account which is an extra database index and I/O overhead.

When the account is in the block itself we can check an unlimited number of signatures in parallel without blocking on any I/O operations. The drawback to this change is increased block size, although the increased performance through transactions-per-second and lower transaction processing latency is an acceptable tradeoff.

Pruned Ledger Support

Any piece of data that’s not in the actual block, for instance the account, balance, or representative, is additional data that needs to be stored or cached in the ledger. This is less of a problem for historical nodes, but for block pruning it means much more data needs to be stored in order to remain consistent. With these changes, each block is a full representation of an account’s state at that point, which allows pruned ledgers to be much more aggressive when removing old blocks.

Efficient Balance and Representative Lookups

Currently an account’s balance is only transmitted on send blocks and an account’s representative is an infrequently referenced piece of data, so calculating a balance at a particular block hash or determining an account’s representative can involve long I/O operations. This is worked around in the existing ledger by using cache tables, though this has the drawback of requiring increased complexity to keep the caches coherent. An additional problem is with light wallet implementations, the current balance is difficult to retrieve, making creating new transactions slightly more difficult to create than it should be. With the implementation of Universal blocks, we can know the balance and representative simply by looking at one block, instead of needing to search down the chain for the last send block that has the balance and then adding up all the receives.