<p>You're seeing two things here: the exact match coin selection algorithm, and the fact that your vsize is computed before adding signatures.</p>
<p><strong>Exact match</strong></p>
<p>The coin selection algorithm in Bitcoin Core tries to find an &quot;exact match&quot; of UTXOs to spend in order to pay, without adding a change output back to you. If the input amount is a bit too large, it is turned into fee. Surprisingly, under certain circumstances this behavior is actually preferable over turning that excess into change.</p>
<p>The observation is that merely creating a change output costs money right now (in terms of fee needed to pay for it), and more money later (in terms of the marginal fee needed to pay for the additional space used by the transaction input that will spend it). That fee is wasteful: if it's possible to not create the change at all, this becomes a cost you never have to pay.</p>
<p>So the conclusion is: if it is possible to construct a transaction without change that overpays <em>less</em> than what it would cost to create and spend change, it is preferable. This is exactly what Bitcoin Core does, using a short-term fee estimation for the creation of the change, and a long-term fee estimation for spending it.</p>
<p>The concept and algorithm for doing this efficiently were first described by <a href="https://bitcoin.stackexchange.com/users/5406/murch">Mark Erhard</a> in his <a href="http://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf" rel="nofollow noreferrer">master's thesis</a>.</p>
<p><strong>vsize before signatures</strong></p>
<p>You're looking at the vsize of the unsigned raw transaction coming out of fundrawtransaction. For fee decision purposes, fundrawtransaction tries to predict the size of the transaction <em>after</em> it is signed.</p>

CC BY-SA 4.0
2020-04-04T21:45:09.387Z
Thanks for the illuminating response, this all makes sense to me now!
Adam Soltys
CC BY-SA 4.0
2020-04-04T23:08:44.800Z
Hi Pieter, in the case of bitcoin everything is working as expected. Now that I get the vsize from the signed tx, the observed rate I'm calculating is almost exactly the rate that was requested. However I'm still seeing a discrepancy between the observed and requested rates for liquidv1 transactions. Could there be an issue with fundrawtransaction not anticipating the signed tx size properly there, or do you have any other insights why things might be different for liquid?
Adam Soltys
CC BY-SA 4.0
2020-04-04T23:09:32.557Z
I have no idea, sorry! You may want to open an issue for that.
Pieter Wuille
CC BY-SA 4.0
2020-04-12T04:38:01.517Z
It turned out I wasn't blinding the liquid transaction before signing it. https://github.com/ElementsProject/elements/issues/852
Adam Soltys
CC BY-SA 4.0
2020-04-04T19:13:06.170Z
2020-04-04T19:13:06.170Z
2020-06-16T11:10:03.350Z
Pieter Wuille
<p>I'm passing an unfunded proposed tx and feeRate param to fundrawtransaction which gives me back the hex of the tx with inputs selected and its fee. I'm not passing a conf_target or estimate_mode. I pass the resulting hex to decoderawtransaction to get the size/vsize of the tx.</p>

<p>I'm trying to check the actual fee rate of the tx by calculating <code>fee * 1000 / vsize</code> but it doesn't seem to match the rate that I passed in as a parameter. </p>

<p>I've tried with a few different values but the actual rate always seems to come out higher than the requested rate by a factor of about 1.59, give or take a little bit.</p>

<p>So am I calculating the observed rate improperly? Is it even possible to have the resulting fee rate exactly match the one provided by the feeRate parameter?</p>

<p>Here's an example of constructing a tx with amount 0.00073749 and feeRate 0.00001000. Proposed tx from createrawtransaction:</p>

<pre><code>{
  "txid": "de380dec00d86611bab1cfa825a7069ffde31d7fb0c5b91e381ef79b94d927e0",
  "hash": "de380dec00d86611bab1cfa825a7069ffde31d7fb0c5b91e381ef79b94d927e0",
  "version": 2,
  "size": 41,
  "vsize": 41,
  "weight": 164,
  "locktime": 0,
  "vin": [
  ],
  "vout": [
    {
      "value": 0.00073749,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 de525f12f17a495b7903c2c5b306ee07ccad309f",
        "hex": "0014de525f12f17a495b7903c2c5b306ee07ccad309f",
        "reqSigs": 1,
        "type": "witness_v0_keyhash",
        "addresses": [
          "bc1qmef97yh30fy4k7grctzmxphwqlx26vyl5lve86"
        ]
      }
    }
  ]
}
</code></pre>

<p>And the full tx with inputs returned by fundrawtransaction:</p>

<pre><code>{
  "txid": "f78b268f9386ab47dd5c0d36caf3aaff5fa719c7a2b5658ff08132159cb6b8cd",
  "hash": "f78b268f9386ab47dd5c0d36caf3aaff5fa719c7a2b5658ff08132159cb6b8cd",
  "version": 2,
  "size": 369,
  "vsize": 369,
  "weight": 1476,
  "locktime": 0,
  "vin": [
    {
      "txid": "ca6f25d4484ab525fdb907cbce81d3dc9d1974695fcc80639fddfff4b6bca268",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "9b39ee5637d7b0783715be6ce566283024ee2bea33a9d3bd6f415ae5d8f24e5f",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "2f2b7eaccc06ea3856cd5b4666a15161d0fac9053ab2bcbb94a490593c969246",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "b5b2e4e1287438fd8193e1409cdf87181061ab4a3d95f50d2bf1bc2534b2d49c",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "3de9c3690c77f544b0d953c70d97f50bb9790a847bed9972caca960218c6c8f6",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "5e0021645a37473afdff1720da902f0abe183fb48719169e96b5235bb6b09e25",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "f92dbcf77c13d887d8aa77404dc78120c90d055a32b4d51196849affc3866ade",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "e425c6e84bc671bfb3a80bd95d1925007e12483fdcf3a19094bde8a36ae0d9fd",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    }
  ],
  "vout": [
    {
      "value": 0.00073749,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 de525f12f17a495b7903c2c5b306ee07ccad309f",
        "hex": "0014de525f12f17a495b7903c2c5b306ee07ccad309f",
        "reqSigs": 1,
        "type": "witness_v0_keyhash",
        "addresses": [
          "bc1qmef97yh30fy4k7grctzmxphwqlx26vyl5lve86"
        ]
      }
    }
  ]
}
</code></pre>

<p>In this case the fee is 0.00000668 so the rate I calculate is <code>0.0000668 * 1000 / 369 = 0.00001810</code> as opposed to the requested 0.00001000</p>

CC BY-SA 4.0
2020-04-04T06:53:32.210Z
Does the resulting transaction have a change output? And how large is it (in terms of number of inputs and outputs)?
Pieter Wuille
CC BY-SA 4.0
2020-04-04T18:59:40.063Z
Hi Pieter, I just updated the question with an example with just 1 output.
Adam Soltys
<transaction-fees><json-rpc>
Calculating fee rate of tx returned by fundrawtransaction
Adam Soltys
# Calculating fee rate of tx returned by fundrawtransaction

(Asked by: username_0 on 2020-04-04)

I'm passing an unfunded proposed tx and feeRate param to fundrawtransaction which gives me back the hex of the tx with inputs selected and its fee. I'm not passing a conf_target or estimate_mode. I pass the resulting hex to decoderawtransaction to get the size/vsize of the tx.
I'm trying to check the actual fee rate of the tx by calculating fee * 1000 / vsize but it doesn't seem to match the rate that I passed in as a parameter. 
I've tried with a few different values but the actual rate always seems to come out higher than the requested rate by a factor of about 1.59, give or take a little bit.
So am I calculating the observed rate improperly? Is it even possible to have the resulting fee rate exactly match the one provided by the feeRate parameter?
Here's an example of constructing a tx with amount 0.00073749 and feeRate 0.00001000. Proposed tx from createrawtransaction:
{
  "txid": "de380dec00d86611bab1cfa825a7069ffde31d7fb0c5b91e381ef79b94d927e0",
  "hash": "de380dec00d86611bab1cfa825a7069ffde31d7fb0c5b91e381ef79b94d927e0",
  "version": 2,
  "size": 41,
  "vsize": 41,
  "weight": 164,
  "locktime": 0,
  "vin": [
  ],
  "vout": [
    {
      "value": 0.00073749,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 de525f12f17a495b7903c2c5b306ee07ccad309f",
        "hex": "0014de525f12f17a495b7903c2c5b306ee07ccad309f",
        "reqSigs": 1,
        "type": "witness_v0_keyhash",
        "addresses": [
          "bc1qmef97yh30fy4k7grctzmxphwqlx26vyl5lve86"
        ]
      }
    }
  ]
}

And the full tx with inputs returned by fundrawtransaction:
{
  "txid": "f78b268f9386ab47dd5c0d36caf3aaff5fa719c7a2b5658ff08132159cb6b8cd",
  "hash": "f78b268f9386ab47dd5c0d36caf3aaff5fa719c7a2b5658ff08132159cb6b8cd",
  "version": 2,
  "size": 369,
  "vsize": 369,
  "weight": 1476,
  "locktime": 0,
  "vin": [
    {
      "txid": "ca6f25d4484ab525fdb907cbce81d3dc9d1974695fcc80639fddfff4b6bca268",
      "vout": 1,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "9b39ee5637d7b0783715be6ce566283024ee2bea33a9d3bd6f415ae5d8f24e5f",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "2f2b7eaccc06ea3856cd5b4666a15161d0fac9053ab2bcbb94a490593c969246",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "b5b2e4e1287438fd8193e1409cdf87181061ab4a3d95f50d2bf1bc2534b2d49c",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "3de9c3690c77f544b0d953c70d97f50bb9790a847bed9972caca960218c6c8f6",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "5e0021645a37473afdff1720da902f0abe183fb48719169e96b5235bb6b09e25",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "f92dbcf77c13d887d8aa77404dc78120c90d055a32b4d51196849affc3866ade",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    },
    {
      "txid": "e425c6e84bc671bfb3a80bd95d1925007e12483fdcf3a19094bde8a36ae0d9fd",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967294
    }
  ],
  "vout": [
    {
      "value": 0.00073749,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 de525f12f17a495b7903c2c5b306ee07ccad309f",
        "hex": "0014de525f12f17a495b7903c2c5b306ee07ccad309f",
        "reqSigs": 1,
        "type": "witness_v0_keyhash",
        "addresses": [
          "bc1qmef97yh30fy4k7grctzmxphwqlx26vyl5lve86"
        ]
      }
    }
  ]
}

In this case the fee is 0.00000668 so the rate I calculate is 0.0000668 * 1000 / 369 = 0.00001810 as opposed to the requested 0.00001000

**Tags:** transaction-fees, json-rpc

> **Comments:**
> **username_1**: Does the resulting transaction have a change output? And how large is it (in terms of number of inputs and outputs)?  
> **username_0**: Hi Pieter, I just updated the question with an example with just 1 output.  

---

## 1 answers

### Answer by username_1 on 2020-04-04. Score: 1 | Accepted answer

You're seeing two things here: the exact match coin selection algorithm, and the fact that your vsize is computed before adding signatures.

**Exact match**

The coin selection algorithm in Bitcoin Core tries to find an "exact match" of UTXOs to spend in order to pay, without adding a change output back to you. If the input amount is a bit too large, it is turned into fee. Surprisingly, under certain circumstances this behavior is actually preferable over turning that excess into change.

The observation is that merely creating a change output costs money right now (in terms of fee needed to pay for it), and more money later (in terms of the marginal fee needed to pay for the additional space used by the transaction input that will spend it). That fee is wasteful: if it's possible to not create the change at all, this becomes a cost you never have to pay.

So the conclusion is: if it is possible to construct a transaction without change that overpays *less* than what it would cost to create and spend change, it is preferable. This is exactly what Bitcoin Core does, using a short-term fee estimation for the creation of the change, and a long-term fee estimation for spending it.

The concept and algorithm for doing this efficiently were first described by [Mark Erhard](https://bitcoin.stackexchange.com/users/5406/murch) in his [master's thesis](http://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf).

**vsize before signatures**

You're looking at the vsize of the unsigned raw transaction coming out of fundrawtransaction. For fee decision purposes, fundrawtransaction tries to predict the size of the transaction *after* it is signed.

> **Comments:**
> **username_0**: Thanks for the illuminating response, this all makes sense to me now!  
> **username_0**: Hi Pieter, in the case of bitcoin everything is working as expected. Now that I get the vsize from the signed tx, the observed rate I'm calculating is almost exactly the rate that was requested. However I'm still seeing a discrepancy between the observed and requested rates for liquidv1 transactions. Could there be an issue with fundrawtransaction not anticipating the signed tx size properly there, or do you have any other insights why things might be different for liquid?  
> **username_1**: I have no idea, sorry! You may want to open an issue for that.  
> **username_0**: It turned out I wasn't blinding the liquid transaction before signing it. https://github.com/ElementsProject/elements/issues/852  

---

