How Amadeus Protocol Handles High Transaction Throughput: 6 Architectural Techniques Explained
Amadeus Protocol achieves high transaction throughput by combining a UDP-based gossip layer, replica clustering, an ETS-backed transaction pool, batch broadcasting, asynchronous background timers, and optimized socket handling.
The Amadeus Protocol (amadeusprotocol/node) is an Elixir-based blockchain node designed for massive on-chain activity. Its architecture eliminates bottlenecks at every layer—from network communication to consensus signing. Below is a detailed breakdown of how the protocol sustains thousands of transactions per second.
UDP-Based Gossip Layer for Low-Latency Communication
Amadeus Protocol replaces TCP with UDP sockets for inter-node communication. This eliminates connection setup overhead and reduces latency for time-critical messages.
The socket is opened in NodeGenSocketGen using :gen_udp.open/2 with binary mode and active receiving:
# ex/lib/node/node_gen_socket_gen.ex
{:ok, sock} = :gen_udp.open(port, [:binary, {:active, true}, {:ip, {0,0,0,0}}])
All outbound packets use :gen_udp.send/4 for connectionless transmission:
# ex/lib/node/node_gen_socket_gen.ex – lines 59-62
:gen_udp.send(socket, ip, port, packet)
This design choice trades TCP's reliability guarantees for raw speed, which is appropriate for a gossip protocol where message redundancy provides natural fault tolerance.
Replica Clustering with BFT Quorum Logic
Multiple validator replicas run in parallel to distribute consensus work. Each replica only signs a block once a quorum of replicas have locked the height, preventing duplicate signatures and wasted computation.
The coordination happens in ReplicaGen, which enforces the BFT quorum before any signing occurs:
# ex/lib/node/replica_gen.ex
# Replica state management and lock-step signing logic
This approach parallelizes consensus without sacrificing safety—the quorum requirement ensures that a supermajority of honest replicas must agree before any block is finalized.
ETS-Backed Transaction Pool with Asynchronous Cleanup
Incoming transactions are stored in an ETS table for fast, concurrent access. The transaction pool (TXPool) remains compact through periodic purging of stale entries.
The purge runs every 6 seconds via an asynchronous task:
# Called from NodeGen.handle_info(:tick_purge_txpool)
Task.async(fn -> TXPool.purge_stale() end)
The purge logic lives in ex/lib/node/txpool.ex. Using ETS instead of a process dictionary or GenServer state minimizes contention and enables true parallel reads.
Batch Broadcasting to Reduce Per-Message Overhead
The node batches validator and peer messages to amortize network overhead. Default limits are 1000 validators and 10 peers per batch, all sent in a single UDP packet.
The broadcast/2 function in NodeGen implements this:
# ex/lib/node/node_gen.ex
NodeGen.broadcast(my_msg, %{validators: 500, peers: 20})
Batching reduces system call frequency and leverages UDP's ability to send large datagrams efficiently. The function signature accepts an override map for fine-tuned control in high-contention scenarios.
Non-Blocking Background Ticks with Lightweight Processes
All periodic work—heartbeats, ANR cleanup, and transaction pool purging—is driven by :erlang.send_after/3 timers that spawn separate lightweight processes. This keeps the main event loop responsive.
The tick handlers in NodeGen follow a consistent pattern:
# ex/lib/node/node_gen.ex – tick_* handlers
def handle_info(:tick_purge_txpool, state) do
# Schedule next tick and spawn async work
:erlang.send_after(6_000, self(), :tick_purge_txpool)
Task.async(&TXPool.purge_stale/0)
{:noreply, state}
end
This architecture prevents any single maintenance task from blocking consensus or network operations.
Optimized Socket Handling for Deployment Flexibility
The protocol adapts its socket behavior based on deployment mode:
- Solo testnet mode: Skips socket creation entirely, saving resources
- Replica cluster mode: Binds the socket once at startup, then reuses it
The skip_socket logic in NodeGenSocketGen enables this optimization:
# ex/lib/node/node_gen_socket_gen.ex
# Conditional socket creation based on configuration
This conditional approach eliminates unnecessary overhead for developers running local tests while maintaining full networking capabilities for production deployments.
Summary
Amadeus Protocol handles high transaction throughput through deliberate architectural choices at every layer:
- UDP gossip eliminates TCP handshake latency
- Replica clustering parallelizes consensus with BFT safety
- ETS-based TXPool provides lock-free concurrent access
- Batch broadcasting reduces network overhead
- Asynchronous ticks prevent event loop blocking
- Conditional socket creation optimizes resource usage
These techniques combine to enable sustained high throughput without sacrificing the safety properties required of a Byzantine-fault-tolerant consensus system.
Frequently Asked Questions
What transport protocol does Amadeus Protocol use for node communication?
Amadeus Protocol uses UDP for all inter-node gossip. The switch from TCP eliminates connection setup overhead and enables true fire-and-forget messaging. Source code in ex/lib/node/node_gen_socket_gen.ex handles socket creation with :gen_udp.open/2 and transmission with :gen_udp.send/4.
How does the transaction pool prevent unbounded growth?
The TXPool module purges stale entries every 6 seconds via TXPool.purge_stale/0, called asynchronously from NodeGen's :tick_purge_txpool handler. This runs in a separate Task process to avoid blocking the main node. The pool is backed by ETS for O(1) access patterns.
Why batch validator messages instead of sending individually?
Batching reduces system call frequency and amortizes packet header overhead across multiple messages. The NodeGen.broadcast/2 function defaults to 1000 validators and 10 peers per batch, tunable per call. This is critical for UDP performance at scale, where per-datagram overhead dominates small payloads.
What happens in solo testnet mode?
In solo testnet configuration, the node skips UDP socket creation entirely via the skip_socket logic in NodeGenSocketGen. This eliminates unnecessary network resource usage when running without replica peers, making local development and testing more efficient.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →