Calculating Batch Throughput and its Theoretical Limits on Layer 1 Bitcoin
Detailed calculations of Bitcoin TPS for normal and batch transactions
This was first published on reddit on 2022-10-08 and updated on 2022-12-03. I’ve made small adjustments to format, wording, and fixed minor typos.
Summary and TL;DR
Blockchain "throughput" is often measured in Transactions Per Second (TPS), but transactions are a poor indicator of useful actions due to batching. A single batch transaction could have 10-1000 separate internal transfers. In fact, the blocks with the lowest recorded TPS actually have the highest useful actions per second because their average transaction is much larger in size and complexity.
Bitcoin is often quoted to be a 7 TPS network. When it was launched initially, that was the max TPS, but it hasn’t been like that for half a decade. Throughput has gradually declined to 3 TPS over the years, especially after exchanges started making large batch transactions. Ironically, Bitcoin at 3 TPS is more efficient than Bitcoin at 7 TPS.
For example, the theoretically most-efficient 4M WU Bitcoin block would consist of 1 single transaction packed with 32250 individual 31-vByte P2WPKH Bech32 UTXO output addresses. This would make Bitcoin a 0.002 TPS network despite performing at a much-higher 53.7 useful Transfers Per Second (TfrPS), which is a better metric for useful actions. That 53.7 TfrPS is the max transfers you can get on the current version of Bitcoin (as of 2022).
In this analysis of over 2 million Bitcoin transactions, I determined that if Bitcoin's blocks were 100% filled to 4M weight, its TPS throughput given the current mix of transaction types is a disappointing 3.9 TPS. This is a major limitation because if even 1% of the world's population used Bitcoin, they would only be able to make 1 on-chain transaction once every 240 days. This suggests that Bitcoin technically cannot reach mass adoption, at least not on a single layer without completely relying on centralized exchanges. However, this metric is somewhat misleading due to batch transactions.
About 20% of transactions on the Bitcoin network use batching, and this is enough to effectively increase throughput 4.3x from 3.9 TPS to 16.8 TfrPS. That’s still slow, but it’s double the popularly-quoted 7 TPS for Bitcoin.
Other Blockchains: While this analysis focuses on Bitcoin, other blockchains are also able to do this. For example, most EVM blockchains can increase throughput of basic 21000-gas transactions by 2x, which is also a 10x increase over their recorded TPS.
Summary Charts
Normal non-batched transactions typically have 1 input UTXO and 2 output UTXOs (one output is for change). If I were to give one number, it would be for the typical 1:2 Segwit transaction, with a TfrPS of 11.8
Batching Outputs - Max TfrPS: 51-53
Most Output UTXOs are about 31-34 vBytes, so the max TfrPS is similar.
Batching Inputs - Max TfrPS: 11 (Non-Segwit), 18 (Wrapped Segwit), or 24 (Segwit)
Input UTXOs are highly-variable, so the throughput depends on which type.
Intro - Throughput Benchmarks
Throughput is the rate at which data travels through a network. For cryptocurrency networks, this is often measured by Transactions Per Second (TPS) because that's the easiest metric to measure on all networks, and the data is ubiquitous. But this is an inadequate measurement of throughput because it doesn't reflect the true rate of useful actions.
Benchmarks: For gaming computers, there is no single benchmark that covers everything. Instead, they are divided into many different categories such as: single-CPU, multi-CPU, 2D graphics, 3D graphics, physics, ray-tracing, etc. There are also composite benchmarks that attempt to estimate typical usage like: office use, gaming use, watching media, video editing, 3D modeling. One way of benchmarking crypto throughput is to divide into different types of "useful actions".
Useful action: A useful action could be a transfer, swap, NFT mint, contract create/destroy, deposit/withdrawal. For batch transactions, a single batch transaction could contain 5000 useful actions, and a single contract could create 100 NFT mints. So what looks like 1 TPS could actually be 5000 useful Transfers Per Second, which I'll call TfrPS.
Useful action in Bitcoin: Bitcoin does not support advanced smart contracts, so there is only one type of useful action: a transfer. You'd think it would be one of the easier blockchains to benchmark. However, this is far from true due to the numerous different types of addresses and Bitcoin’s stubborn insistence on soft-forking while maintaining backwards compatibility.
Bitcoin now has P2PKH, P2SH, P2WPKH, P2WSH, P2WPKH/P2WSH-within-P2SH, and P2TR addresses, all with different input sizes, output sizes, and signature/witness sizes. This is due to the Bitcoin community's ridiculously unhealthy obsession with avoiding hard forks (e.g. the Segwit 4M weight fiasco that inevitably ended up splitting the community in a hard fork anyways). Each of the combinations of addresses and headers generates a different size of transactions, each with different TPS and TfrPS measurements.
About 20% of Bitcoin transactions are batch transactions, which I consider any transaction with more than 3 UTXOs. These are almost exclusively done by exchanges. I've personally noticed BlockFi and Gemini doing small batch transactions of ~10 UTXOs with my accounts, and Coinbase doing a 1:100 batch transaction with them.
Analysis
Tools:
Most of my data is sourced from blockchair.com, blockchain.com, blockstream.info, and btcscan.org for analyzing blocks and transactions. Blockchair was particularly useful because it provides a bulk data download way faster than most API services. You gotta love the speed of traditional databases. I used Google Sheets to compile the results, which was annoyingly slow due to its 10M-cell limit, so I had to optimize by splitting calculations across multiple sheets. Lastly, I used this calculator to double-check my work.
Overall Measurements from the Blockchain:
Overall, across 1271 blocks and 2.19M transactions, there were 1.47B bytes, 3.82B weight units (WU), and 9.60B transfers. On average, the blocks would've been 1.54MB on average if full. The actual TPS with the partially-full blocks was 2.88. Had the blocks been full, they would have seen a throughput of 3.9 TPS and 16.8 TfrPS.
Transaction count varied as much as 10% from day to day. However, the results after correcting for block fullness were quite stable.
Daily TPS range: 2.8-3.2
Daily TfrPS range: 11-13
Daily TPS with 100%-full blocks: 3.9
Daily TfrPS with 100%-full blocks: 16.8, which is 4.3x the max TPS
What this means is that the Bitcoin blockchain is getting 4.3x as many useful actions (TfrPS) as what the TPS metric suggests.
Transfers per Transaction:
Most single-transfer transactions actually contain 3 UTXOs (1 input, 2 outputs) because there is a change output UTXO.
Within the 2M transactions, here's the percent breakdown of what kind of transactions were on the blockchain:
Size Details
Block size: Each Bitcoin block has a maximum of 4M weight units (WU), mined an average of once per 10 minutes or 6667 WU/s. On average, 75% of the daily block space was filled.
Transaction weight = 3x base size + 1x full size = 4x (header + inputs + outputs) + 1x witness size
UTXO sizes (vBytes)
1 vByte = 4 weight units (WU)
These vByte sizes include the Witness size. Sometimes the size is 1-2 vBytes smaller due to the Witness having leading zeroes that get trimmed.
Bitcoin "Scripts" are usually just Multisig addresses
Transactions also have a header, which is normally 10-11 vBytes.
All the large batch transactions have a good mix of output address types because their recipients are random. On average, they're around 31-32 vBytes since Multisig and Taproot outputs are uncommon.
Common Transaction Weights
These are the UTXO combinations I noticed the most often in the 400-1000 WU range. Almost all batch transactions fall beyond this range, and they vary too much in size to be included here. The largest ones were ~400000 WU.
437-439 - Segwit to P2WPKH (common)
441-442 - Segwit to P2SH (common)
449-450 - Segwit to P2PKH (common)
561-574 - Segwit to 2x various (common)
658-661 - P2SH to 2x various
756-764 - P2PKH to various
833-845 - 2x Segwit to 2x various
885-900 - P2PKH to 2x various, Segwit to 3x various
Distribution of Transactions by Weight Units
Theoretical Limits to Batch throughput
Common Segwit (P2WPKH) transactions: You can increase throughput from 11.8 TfrPS to 53.7 by batching outputs, and from 11.8 TfrPS to 24.5 by batching inputs.
Common Wrapped Segwit (P2WPKH-in-P2SH) transactions: You can increase them from 12.4 to 18.3 TfrPS with batch inputs.
Note that these are purely theoretical limits because there will always be a mix of different types of transactions. You can't expect everyone to join into a single transaction. That would require everyone to use a single centralized exchange. And you can't expect users to only batch outputs, not inputs. This is why the real max throughput is 16.8, which is far lower than the theoretical limit of 53.7.
Side Notes
Outliers
Smallest transactions: Technically, the smallest transactions are [396-397 WU, 1:1 P2TR (Taproot) to P2WPKH] transactions, but they're very rare (< 0.5% of transactions), and they're not used in batch transactions. So they're not relevant to this analysis.
Largest transactions: Technically, the largest batch transactions date back to 2015. They each held 20000 transfers like this one: [30b3b19b4d14fae79b5d55516e93f7399e7eccd87403b8dc048ea4f49130595a], but they were useless wasted block space sent to OP_RETURN without any metadata.
Compared to Ethereum
For comparison, even without batching, Ethereum can normally reach 60 TPS for basic ETH transfers (21k gas), and 24 TPS for ERC-20 token transfers assuming the 15M-gas limit on 12s blocks.
With batch Txs, Ethereum reaches 123 TfrPS for ETH tranfers and 81 TfrPS for ERC-20 token transfers
Ethereum can also expand further to 30M gas per block to double that throughput, but 30M blocks are not sustainable without have gas prices skyrocket.