Why is a minRelayTxFee of 1000 sat/kb not equivalent to 250 sat/kw? 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 &gt; 1000 * virtual size 
    * feerate-per-kw * weight &gt; 1000 * (3 * weight / 4) 
    * feerate_per-kw &gt; 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.
I thought vbytes were equal to weight units divided by 4

It is [1], 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 :
&gt;&gt;&gt; def bitcoind_fun(tx_weight, feerate_perkw):
...     fees = tx_weight * feerate_perkw // 1000
...     print(&quot;Your transaction will pay {} sats of fees, is {} WU large (a feerate of {}sat/Kw)&quot;.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(&quot;bitcoind reads your transaction as paying {} sats of fees for a transaction of {} vbytes, so a {}sat/perKvb feerate&quot;.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 :
&gt;&gt;&gt; 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
&gt;&gt;&gt; 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
&gt;&gt;&gt; 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 :
&gt;&gt;&gt; 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
&gt;&gt;&gt; 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
&gt;&gt;&gt; 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.

[1] Excluding sig OPs limits that artificially increases the virtual size to further prevent DOS.
PS: In the same vein, see https://github.com/bitcoin/bitcoin/issues/13283.