Insights

Where the XRP Ledger Runs Out of Room

The XRP Ledger Testnet carried 1,520 successful payments a second for half an hour. At 2,000 a second, every server on the network stopped on the same ledger for about 2 minutes. The limit is not signing or storage: it is six places in the rippled server where work has to wait its turn.

Measured 2026-09-23rippled 2403670d

What happens as the load rises

With no load a Testnet ledger closes every 3.5 seconds. At 1,520 payments a second, ledgers held a median of 7,600 transactions and took 4.9 seconds, with one in a hundred taking 9.5 seconds or more. Each ledger got bigger and slower at the same time, which is how a limit shows itself: past a point, adding transactions adds time rather than throughput.

At 2,000 a second the network did not slow down — it stopped. The last consensus round reported taking 15.06 seconds with no validator proposals counted, which is the longest a validator will wait for others before moving on (ledgerMaxConsensus = 15 s). Ripple's own servers and ours all sat on the same ledger until the load was removed; ledgers resumed within a minute of it stopping.

The six places work waits

01

Every server has to see every transaction

A payment reaches one server and is passed from server to server. Each copy that arrives becomes a job in the receiving server's queue. When more than 250 of those jobs are already waiting, the server drops the incoming transaction without looking at it.

Under load: 118,912 transactions dropped this way by one server during the run.

PeerImp.cpp:1387Config.h:228

02

Disagreement turns into voting

Validators only agree on a ledger once they agree on its exact set of transactions. Any transaction one of them has and another does not becomes a dispute, voted on in rounds that need 50%, then 65%, 70% and finally 95% agreement. Missing sets are fetched from peers in 250 ms steps.

Under load: Dropped transactions from the stage above are exactly what creates these disputes.

ConsensusParms.h:149TransactionAcquire.cpp:32

03

Validators wait up to 15 seconds for the slowest

A round cannot finish in under 1.95 seconds, and a validator waits up to 15 seconds for others that are behind before giving up on them.

Under load: When the load reached 2,000 a second, the round took 15.06 s — the 15-second limit — and no validator's proposal counted. Testnet stopped for about 2 minutes.

ConsensusParms.h:79ConsensusParms.h:88

04

One writer for the open ledger

New transactions are applied in batches, one batch at a time, while holding the server's two main locks. Before each batch the whole open ledger — every transaction already in it and every account it changed — is copied. The busier the ledger, the more each batch costs.

Under load: Ripple's own 2023 trace: 2,179 transactions took 52 ms to apply and 818 ms to set up for, in one second.

NetworkOPs.cpp:1540OpenLedger.cpp:67OpenView.cpp:78

05

Closing a ledger stops everything else

When a ledger closes, the agreed transactions are applied again in up to three passes to build it. Then the next open ledger is rebuilt — including every transaction still waiting in the queue — under the same two locks, so nothing new is applied in the meantime.

Under load: This step averaged 506 ms and peaked at 1,775 ms per ledger.

BuildLedger.cpp:108RCLConsensus.cpp:637

06

The fee queue grows a fifth per ledger

At the minimum fee a ledger takes what the server expects it to hold, starting at 32 transactions and growing by 20% per ledger while ledgers close on time — and shrinking the moment one is slow. Each account can have at most 10 transactions waiting.

Under load: From a standing start it takes about 25 ledgers to reach 7,600 a ledger; one slow ledger sends it back down.

TxQ.cpp:139TxQ.h:165

The first three are about agreement between validators; the last three are about one server doing its own work. They feed each other: a server busy closing a ledger falls behind on relayed transactions, drops some, and the next round has more to argue about.

What is not the limit

Applying a payment is cheap. Ripple's trace measured 24 microseconds per transaction — a theoretical 40,000 a second on one core. Signatures are checked once per transaction per server and the result remembered, in parallel across the job queue. Neither is where the time goes. The time goes to waiting: for a lock, for a copy, for other validators.

Ways to raise it

Apply transactions in fewer, larger batches

Ripple did this in 2023: wait 100 ms between batches, so the open ledger is copied a handful of times per second instead of hundreds. In Ripple's trace the time spent holding the lock fell from 970 ms to 122 ms in a second. It was merged (#4504) and then reverted three months later (#4852), the revert saying there was “no evidence that any problems were introduced” — it was pulled as a suspect in an unrelated fault and never put back.

Stop copying the whole open ledger

The batching fix makes the copy rarer; changing the open ledger so a batch only records what it changes would make it cheap. The copy constructor (OpenView.cpp:78) duplicates both the transaction list and every changed account for every batch.

Let validators keep more incoming transactions

The 250-job limit that drops relayed transactions is a setting, and a server may raise it to 1,000 (Config.h:229). Fewer dropped transactions means fewer disputes, and disputes are what drag a round towards its 15-second limit.

Relay each transaction to fewer peers

rippled already contains a reduced-relay mode that sends each transaction to a quarter of peers and lets the rest ask for it, cutting duplicate copies. It is off unless a server turns it on (Config.h:264).

More worker threads on validators

Signature checks and relayed transactions run on the server's job queue; the server under test here had 6 threads. Signatures are checked once per transaction and then remembered (apply.cpp:36), so they spread well across more threads — the locks above do not.

Write to disk without holding up consensus

Ripple also made disk writes asynchronous in 2023 (#4503). It was reverted because writes blocked during online deletion and put servers out of sync (#4882). The idea stands; that bug has to be solved first.

Where Ripple's 3,400 comes from

Ripple's engineering blog reported “over 3400 sustained transactions per second” in July 2023 (Improving XRP Ledger Throughput, Mark Travis), measured “in a distinct environment to avoid disrupting service on the mainnet or other test networks”, with three changes it names — #4503, #4504 and #4505. Two of the three have since been reverted. A public network with validators run by different people, on different machines, across the world, is a harder place to agree than a lab, and it is running without those two changes.

Method

Load: XRP payments between 3,000 accounts at the minimum fee, measured in 1,500 Payments a Second on the XRP Ledger Testnet. Node figures are the server's own counters (server_info, consensus_info, fee) read every two seconds. Ledger times are wall-clock times at which each ledger was first seen validated, because a ledger's recorded close time is rounded to at least ten seconds (LedgerTiming.h:16). Source: rippled develop at 2403670d; Testnet ran rippled 3.4.0.

Related reading

1,500 Payments a Second on the XRP Ledger Testnet · Half of Solana's Transactions Are Not Transactions