§ 05 · Transactions
Fees and vsize
What a transaction pays, and how its size is measured
On this page 8 sections
A feeFee: What a transaction leaves for the miner: the total of its inputs minus the total of its outputs. The miner who puts it in a block keeps it. is the part of the inputs that no output claims. The miner who includes the transaction collects it, on top of the new coins in the block reward.
Nothing in a transaction says “fee”. You find it by subtraction. And since block space is what’s scarce, fees are compared per unit of size: grains per virtual byteFee rate: A transaction's fee divided by its size, in grains per vbyte. Miners prefer higher rates; nodes won't pass on anything below 1 grain per vbyte.. This page explains both numbers and the limits around them.
Try it
Pick a transaction shape and a fee rate and see what it costs.
Where is the fee?
In the gap between inputs and outputs. Take the real payment from block 130,825:
| Grains | |
|---|---|
Input: 33218153…:683 |
495,654,555 |
| Output 0 (change) | − 295,646,640 |
| Output 1 (payment) | − 200,000,000 |
| Fee | 7,915 |
The input’s value isn’t in the transaction either; nodes look it up in the UTXO set. That’s why a node needs the outputs being spent before it can even tell what fee a transaction pays.
What is vsize?
A size in which witness bytes count a quarter. Pearl calls it virtual size, measured in vbytesVirtual byte (vbyte): Pearl's unit of transaction size: ordinary bytes count in full and witness bytes count a quarter each. A block can hold at most 1,000,000 vbytes.:
- Base size is the transaction without marker, flag and witness: the bytes that make the txid.
- Witness size is everything else: the marker and flag (2 bytes) plus all witness stacks.
- The division rounds up, so even 1 to 3 witness bytes cost a full vbyte.
func CalcVsize(baseSize int, witnessSize int) int64 {
return int64(baseSize + (witnessSize+WitnessScaleFactor-1)/WitnessScaleFactor)
} For the payment: 137 base bytes + ⌈68 ÷ 4⌉ = 137 + 17 = 154 vbytes, at 7,915 ÷ 154 = 51.4 grains per vbyte.
| Field | Bytes | Value |
|---|---|---|
| Version version | 4 @0 | 1 int32 little-endian. Pearl wallets and pearld coinbases use version 1; relay policy accepts 1-2. |
| Marker marker | 1 @4 | 0x00 Segwit marker (BIP-144): says witness data follows the outputs. |
| Flag flag | 1 @5 | 0x01 Witness flag; 0x01 is the only value Pearl accepts. |
| Input count vin.length | 1 @6 | 1 CompactSize number of inputs. |
| Previous txid vin[0].txid | 32 @7 | 33218153e215d1a1e80941850a696af178fc83bd6cf266be92e7ba9170553959 The transaction being spent, stored byte-reversed (internal order); shown here in normal display order. |
| Output index vin[0].vout | 4 @39 | 683 Which output of that transaction is spent (uint32 LE). |
| scriptSig length vin[0].scriptSig.length | 1 @43 | 0 Always 0 for non-coinbase inputs in Pearl: every spend uses the witness instead. |
| Sequence vin[0].sequence | 4 @44 | 0xffffffff Final (0xffffffff): no RBF signal, no relative locktime, and locktime is ignored for this input. Pearl wallets use this. |
| Output count vout.length | 1 @48 | 2 CompactSize number of outputs. |
| Amount vout[0].value | 8 @49 | 295,646,640 grains (2.95646640 PRL) int64 little-endian, in grains (1 PRL = 100,000,000 grains). |
| Script length vout[0].scriptPubKey.length | 1 @57 | 34 CompactSize length of the locking script. |
| Locking script vout[0].scriptPubKey | 34 @58 | prl1p674s9jt2xs4amk6aq7ul867kcp8qwll5zsvpzzu6revewsu5z6eqv9d5z4 OP_1 OP_PUSHBYTES_32 <output key Q>: a Taproot output. |
| Amount vout[1].value | 8 @92 | 200,000,000 grains (2.00000000 PRL) int64 little-endian, in grains (1 PRL = 100,000,000 grains). |
| Script length vout[1].scriptPubKey.length | 1 @100 | 34 CompactSize length of the locking script. |
| Locking script vout[1].scriptPubKey | 34 @101 | prl1pvt5a5d5z42egswfv7uscht7rv2rj3z4m8n3qp3w35592ydq88v4seuhn70 OP_1 OP_PUSHBYTES_32 <output key Q>: a Taproot output. |
| Witness items witness[0].length | 1 @135 | 1 Number of witness stack items for input 0. |
| Schnorr signature length witness[0][0].length | 1 @136 | 64 CompactSize length of this witness item. |
| Schnorr signature witness[0][0] | 64 @137 | 4686c7014749649b25555874c7772ecb7a44e85454893ed5888db11ebcdc82a22d74ce1a1671d02810f5ba1dca3277409e95a653ba9644099f7da26be7a86ba2 64-byte BIP-340 signature (R.x ‖ s) with SIGHASH_DEFAULT: a Taproot key-path spend. |
| Locktime locktime | 4 @201 | 0 0: no time lock. |
The highlighted bytes, plus the 00 01 after the version, are the 68 discounted ones.
Real transactions, measured
| Transaction | Size | Base | Witness | vsize | Fee | Rate |
|---|---|---|---|---|---|---|
| Payment, 1 in, 2 out | 205 | 137 | 68 | 154 | 7,915 | 51.4 |
| Payment, 2 in, 2 out | 312 | 178 | 134 | 212 | 10,650 | 50.2 |
| OP_RETURN, 1 in, 3 out | 253 | 185 | 68 | 202 | 10,200 | 50.5 |
| P2MR funding, 2 in, 2 out | 312 | 178 | 134 | 212 | 10,803 | 51.0 |
| P2MR 2-of-2 spend, 1 in, 3 out | 387 | 180 | 207 | 232 | 1,000 | 4.3 |
| Coinbase, block 130,825 | 216 | 180 | 36 | 189 | none | – |
Sizes in bytes, fees in grains, rates in grains per vbyte. The P2MR spend shows the discount at work: 207 bytes of witness, two signatures and a script, cost only 52 vbytes.
Why discount the witness?
Two reasons, both inherited from Bitcoin’s segwit:
- Witness data can be dropped later. Once a block is deep in the chain, nodes don’t need old signatures to know the current set of coins. Base data, which defines that set, is the expensive part.
- It makes spending cheaper than creating. Inputs carry witnesses; outputs don’t. Discounting witnesses nudges wallets to consolidate coins rather than fragment them.
How does a wallet know the size before signing?
Because every piece of a Pearl key-path spend has a fixed size. An input is 41 base bytes plus a 66-byte witness (count, length, 64-byte signature); a Taproot or P2MR output is 43 bytes; the rest is 10 bytes plus the 2-byte marker and flag. With n inputs and m outputs (under 253 of each):
One input, two outputs: 10 + 41 + 86 + 17 = 154. Two and two: 10 + 82 + 86 + 34 = 212. Both match the real transactions in the table.
What’s the minimum fee?
1 grain per vbyte. Nodes won’t relay or mine a transaction paying less; the payment above would have needed at least 154 grains.
The code calls this DefaultMinRelayTxFee = 1000, “in Grain/1000 bytes”. Read “bytes” as vbytes: Pearl’s mempool computes every fee rate as fee × 1,000 ÷ vsize, and so does the wallet. Two unit traps follow:
- “Per kB” means per 1,000 vbytes, everywhere in Pearl’s node and wallet.
- RPC fee arguments are in PRL, not grains. Oyster’s
feerateperkbof 0.00001 PRL/kB = 1,000 grains per 1,000 vbytes = 1 grain per vbyte, which is oystercli’s default. The plain RPC send calls have no default: the caller must pass a rate.
What do transactions actually pay?
A snapshot, not advice. On 2026-10-20 Pearl’s Blockbook estimated, in PRL per 1,000 vbytes:
| To confirm within | Estimate | Grains per vbyte |
|---|---|---|
| 1 block | 0.00051294 | about 51.3 |
| 2 blocks | 0.00002432 | about 2.4 |
| 3 blocks | 0.00001005 | about 1.0 |
| 6, 12 or 25 blocks | 0.00001 | 1.0 (the floor) |
Most payments in recent blocks paid about 50 to 51 grains per vbyte, matching the 1-block estimate. Some paid far less and still confirmed: the P2MR spend above paid 4.3. More than half of recent blocks carried only their coinbase, so space is rarely short.
Remember that Pearl’s wallet doesn’t signal replace-by-fee, so its transactions can’t be replaced by a higher-fee version after sending.
How big can things get?
- Block
- 1,000,000 vB
- certificate not counted
- Standard transaction
- 100,000 vB
- relay policy
- Any transaction
- 1,000,000 vB
- consensus
- Minimum relay fee
- 1 grain/vB
- 1,000 grains per 1,000 vB
- Dust (Taproot, P2MR)
- 333 grains
- smallest relayed output
- Unconfirmed chain
- 25 txs
- and 101,000 vB of ancestors
A block’s vsize counts its 108-byte header, its transactions and their witnesses (discounted), but not the ~60 KB proof certificate that travels with it. There’s also a floor: Pearl’s mempool rejects transactions whose base size is under 65 bytes.