4

Naively, we would expect a minRelayTxFee of 1000 sat/kb to correspond to 250 sat/kw. However, apparently this is not so according to this issue (ACINQ), which also references this issue (c-lightning).

  /** 
    * why 253 and not 250 since feerate-per-kw is feerate-per-kb / 250 and the minimum relay fee rate is 1000 satoshi/Kb ? 
    * 
    * because bitcoin core uses neither the actual tx size in bytes or the tx weight to check fees, but a "virtual size" 
    * which is (3 * weight) / 4 ... 
    * so we want : 
    * fee > 1000 * virtual size 
    * feerate-per-kw * weight > 1000 * (3 * weight / 4) 
    * feerate_per-kw > 250 + 3000 / (4 * weight) 
    * with a conservative minimum weight of 400, we get a minimum feerate_per-kw of 253 
    * 
    * see https://github.com/ElementsProject/lightning/pull/1251 
    **/ 
   val MinimumFeeratePerKw = 253

I thought vbytes were equal to weight units divided by 4 and rounded up, so I don't understand where (3 * weight) / 4 comes from.

  • 1
    I think this is a typo. It's (3 + weight) / 4, not (3 * weight) / 4. – Pieter Wuille May 14 at 18:41
3

I thought vbytes were equal to weight units divided by 4

It is *, but rounded up to the next integer, so the implementation in bitcoind is :

int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
    return (std::max(nWeight, nSigOpCost * bytes_per_sigop) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}

(Where WITNESS_SCALE_FACTOR = 4).

In addition, bitcoind not only uses vbytes for user interface but also for mempool logic and the DEFAULT_MIN_RELAY_TX_FEE constant is set in vbytes :

static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;

In order to check it for standardness bitcoind will compute your transaction size as rounded up (if not a multiple of 4), and will record your transaction feerate as rounded down.
It will then compare this to the minimum relay feerate (1000) : a feerate of 250sat per KW will pass only if the size of your transaction (in weight units) is a multiple of 4.

It might be clearer with code, here is a Python function which illustrates this behaviour :

>>> def bitcoind_fun(tx_weight, feerate_perkw):
...     fees = tx_weight * feerate_perkw // 1000
...     print("Your transaction will pay {} sats of fees, is {} WU large (a feerate of {}sat/Kw)".format(fees, tx_weight, feerate_perkw))
...     tx_vbytes_for_bitcoind = (tx_weight + 3) // 4
...     tx_feerate_vbytes_for_bitcoind = fees * 1000 // tx_vbytes_for_bitcoind
...     print("bitcoind reads your transaction as paying {} sats of fees for a transaction of {} vbytes, so a {}sat/perKvb feerate".format(fees, tx_vbytes_for_bitcoind, tx_feerate_vbytes_for_bitcoind))

Which if you run with a tx_weight which is a multiple of 4 will pass, otherwise it won't :

>>> bitcoind_fun(1600, 250)
Your transaction will pay 400 sats of fees, is 1600 WU large (a feerate of 250sat/Kw)
bitcoind reads your transaction as paying 400 sats of fees for a transaction of 400 vbytes, so a 1000sat/perKvb feerate
>>> bitcoind_fun(1601, 250)
Your transaction will pay 400 sats of fees, is 1601 WU large (a feerate of 250sat/Kw)
bitcoind reads your transaction as paying 400 sats of fees for a transaction of 401 vbytes, so a 997sat/perKvb feerate
>>> bitcoind_fun(1602, 250)
Your transaction will pay 400 sats of fees, is 1602 WU large (a feerate of 250sat/Kw)
bitcoind reads your transaction as paying 400 sats of fees for a transaction of 401 vbytes, so a 997sat/perKvb feerate

So we use 253 as the feerate floor to always be safe :

>>> bitcoind_fun(1600, 253)
Your transaction will pay 404 sats of fees, is 1600 WU large (a feerate of 253sat/Kw)
bitcoind reads your transaction as paying 404 sats of fees for a transaction of 400 vbytes, so a 1010sat/perKvb feerate
>>> bitcoind_fun(1601, 253)
Your transaction will pay 405 sats of fees, is 1601 WU large (a feerate of 253sat/Kw)
bitcoind reads your transaction as paying 405 sats of fees for a transaction of 401 vbytes, so a 1009sat/perKvb feerate
>>> bitcoind_fun(1602, 253)
Your transaction will pay 405 sats of fees, is 1602 WU large (a feerate of 253sat/Kw)
bitcoind reads your transaction as paying 405 sats of fees for a transaction of 401 vbytes, so a 1009sat/perKvb feerate

By the way the comment in the code you put is wrong : it's not (3 * weight) / 4 but (3 + weight) / 4.


* Excluding sigop stuff.

PS: In the same vein, see https://github.com/bitcoin/bitcoin/issues/13283.

| improve this answer | |
  • I see, so the core issue is rounding up when calculating the tx size, and rounding down when calculating the fee rate. That is very tricky. Thank you for such a clear explanation! 🙏 🙏 – Darius May 14 at 23:21
  • 1
    The round down is actually a consequence of the round up but yes that's the point. You are welcome :) – darosior May 15 at 9:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.