// #Bitcoin
Bitcoin transactions must pay for their spot on the blockchain. The fee they pay isn’t static or based on the amount of bitcoin moving. It is based on the size of transaction in bytes. A complicated transaction, which takes more bytes to describe (e.g. big long script), needs to pay more. This makes sense since it has the potential to take up all the space in a block and crowd everyone out.
A transaction’s fee is implicit, fee = sum of all inputs - sum of all outputs
. All transaction fees in a block are included in the block reward for the miner, reward = block subsidy + sum of all fees
. The sum of the outputs of the coinbase transaction must equal the reward for the block.
A user needs to pick a fee when defining a transaction. They obviously want this fee to be as small as possible, just enough to get their transaction on chain. Predicting good fees is a bit of an art because it depends on the current state of the mempool, the queue of transactions waiting to get into blocks. If the pool is empty, simple, anything gets in for almost no fee. Things get more complicated once there is a market for block space.
Since transactions are unique and can come in all shapes and sizes, talking in terms of “average fee” is pretty useless. A more helpful signal is the feerate, what is the cost in bitcoin per byte of transaction. Unfortunately, this rate is not as straightforward as it sounds. Generally the smallest divisible unit of bitcoin, satoshis, are used for the numerator. And in the pre-segwit days, the denominator could just be bytes. But segwit introduced a concept where not every byte in a transaction has the same weight. A discount is given to the witness data which is now mapped to input rather than stored directly in it. Another way to view this is that the non-witness data is “heavier”. And its actually four times heavier, but won’t get into the whys here.
Segwit introduced weight units (WU). Witness data is 1 WU per byte, non-witness data is 4 WU per byte. This allows for an easy, precise calculation for the number of weight units a transaction takes up, weight = (non-witness size × 4) + witness size
. And the maximum block size is now defined in weight units. Cool, let’s stop here and just use that instead of bytes! Well, if bitcoin was designed this way from the start, we would. But the trouble is that segwit was as soft fork, so pre-segwit transactions are still totally cool. And while it is easy years later to say “let’s just use weight units!”, segwit was introduced years after the genesis block. A lot of tooling had been built around the very reasonable sats/byte
feerate, it was a lot to as for everything to hop to weight units at the same time.
A non-segwit transaction (a legacy transaction) can still easily calculate its weight, it’s just 4x its total bytes since it is not using the witness space. Easy to see why they take up more “virtual” bytes. Can legacy software understand this? Well, what if we just divide all transaction weight unit amounts by four? That way a segwit transaction is still smaller in bytes, and the old tooling can easily see it and compare it with legacy transactions. Since a segwit transactions “raw” byte count will still be higher than this calculation the special unit was given a new name, virtual size measured in virtual bytes, vsize = (transaction weight ÷ 4) rounded up to the nearest integer
. The goal was to avoid a sudden 4x jump in feerates, even though the units changed, like “10 sat/byte” to “2.5 sat/WU”. Instead it is now “2.5 sat/vbyte”, which is technically different than sat/bytes
, but super easy to compare and make the transition smooth. Purely a “for the humans” thing.
The virtual size calculation introduces some loss of precision with that “round up to the nearest integer” bit. A transaction with 101 WU is 26 vB and a transaction with 103 WU is also 26 vB. Does this cause any practical issues?
Transaction A: 100 WU -> 25 vB -> at 10 sat/vB pays 250 sats
Transaction B: 103 WU -> 26 vB -> at 10 sat/vB pays 260 sats
Transaction C: 104 WU -> 26 vB -> at 10 sat/vB pays 260 sats
Transaction B pays for one extra vB.
Transactions with weights not divisible by four pay for some extra virtual bytes if they go purely off a sat/vB feerate. Although the maximum damage is 3 vB which is usually very small compared to the whole transaction weight. Rounding up still makes more sense from a conservative perspective, that way rounding doesn’t lead to a block being too large. But if creating a ton of transactions, it might make sense to work in WU directly to avoid any rounding.
It has been a few years since the segwit activation, so whats the most popular feerate these days? Bitcoin Core is still using sats per vbyte on most of their interfaces, so might be here to stay.
There is another practical advantage to using a “larger” base unit than WU. It keeps the feerate from being a really small fraction. Let’s say the mempool is empty, low congestion, and there is a predicted feerate of 1 sat/vB. That is equivalent to a feerate of 0.25 sat/WU. It is kind of annoying that the feerate needs to be stored as floating point. Generally, bitcoin doesn’t support floating point, although that doesn’t apply to wallet software dealing with feerates, an entirely off-chain concept. Bumping the base unit, effectively multiplying the top (like we can see with WU to vB which is 4x), avoids some pain. Some software has opted for using kWU, kiloweight units, which is 1,000 WU. So 1000x, which pulls those small feerates out of float land.
Although larger base units do introduce the possible footgun to way overpay a fee. If you take a 1100 WU transaction and round it to 2 kWU to work with a sat per kWU feerate you pay for an extra 900 WU. The larger the base unit, the more precise a feerate can be represented as an integer, but also introduces a risk for larger over-payment. But maybe best case is transmitting feerates as integers and then letting wallet software perform the necessary calculations at their desired precision, dealing with any fractions where precision could be lost in rounding.
1. Convert to precise units: 250 sats/kwu = 0.25 sats/wu
2. Calculate exact fee: 1234 wu × 0.25 sats/wu = 308.5 sats
3. Apply appropriate rounding:
- Ceiling: 309 sats (higher chance of quick confirmation)
- Floor: 308 sats (optimizes fee)
Practical example for a 1234 wu transaction with a fee rate of 250 sats/kwu, the error is bounded to 1 satoshi.