[amount] Add support for negative fee rates - #7796
Conversation
|
Negative fee rates imply that you pay a smaller, more negative fee the larger the transaction? What do negative fees even mean, steal from the miner? Or is this so that anti-transactions of negative size pay a positive fee? I'd say this is an edge case better to get rid of (e.g. assert or throw an error). |
|
Uninformed guess: maybe they are relevant for priotizetransaction?
|
|
According to @MarcoFalke they already don't work on 64-bit architectures, which is probably 90%+ of all nodes. Better to remove it for 32 bit as well. |
There was a problem hiding this comment.
Instead of the temporary variable, why not just:
nSatoshisPerK = nFeePaid * 1000 / static_cast<int64_t>(nSize);
Also at least theoretically you should handle the case where nSize is outside the range of int64_t, though I doubt someone will ever care about transactions that large.
There was a problem hiding this comment.
If it is used more than once, you'd rather want to do the cast only once. I guess an alternative would be to change it in the constructor arguments, but that is less verbose, imo.
There was a problem hiding this comment.
I guess an alternative would be to change it in the constructor arguments
I thought of that, but didn't mention it at second thought. Before you know it people will want full support for negative sizes as well. The appropriate type is size_t.
There was a problem hiding this comment.
This would require a cast in 4 places instead of two (see diff below) but I am happy to apply the diff an squash. Please let me know how to proceed so we can finalize this.
diff --git a/src/amount.cpp b/src/amount.cpp
index 7b8618d..3966c5f 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -13,8 +13,7 @@ CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
- int64_t nSize = int64_t(nBytes_);
- if (nSize > 0)
- nSatoshisPerK = nFeePaid * 1000 / nSize;
+ if (int64_t(nBytes_) > 0)
+ nSatoshisPerK = nFeePaid * 1000 / int64_t(nBytes_);
else
nSatoshisPerK = 0;
@@ -24,9 +23,8 @@ CAmount CFeeRate::GetFee(size_t nBytes_) const
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
- int64_t nSize = int64_t(nBytes_);
- CAmount nFee = nSatoshisPerK * nSize / 1000;
+ CAmount nFee = nSatoshisPerK * int64_t(nBytes_) / 1000;
- if (nFee == 0 && nSize != 0) {
+ if (nFee == 0 && int64_t(nBytes_) != 0) {
if (nSatoshisPerK > 0)
nFee = CAmount(1);|
Ok, at least document this then, for example in the doc comment of the constructor. It's extremely unintuitive to me and probably to others reading this code as well. |
|
Ok, will add the doc later... |
|
ping @sdaftuar |
|
I think it's probably better to fix support for negative fee rates on 64-bit platforms, because (a) fixing the But to be fair, I'm surprised that no one has complained about this before, because as far as I can tell, up until 0.12, if you used prioritisetransaction to apply a negative feerate, then the mining code would immediately select it as a super-high-fee transaction. (I stumbled upon this behavior while working on #7063.) So, concept ACK. I agree with @laanwj's comment about the cast. Also, I think it probably makes most sense to enforce the property that Also, we should add a unit test that exercises the constructor |
7777bd2 to
fadd138
Compare
Makes sense, done.
Done. |
fa7c3b8 to
faf4ef7
Compare
Currently negative fee rates are not supported on archs of 64-bit or more
fa2da2c to
11114a6
Compare
|
Before on 64-bit: After: |
1b83a0d to
fa2da2c
Compare
|
utACK facf5a4 |
|
|
||
| if (nFee == 0 && nSize != 0 && nSatoshisPerK > 0) | ||
| nFee = CAmount(1); | ||
| if (nFee == 0 && nSize != 0) { |
There was a problem hiding this comment.
Couldn't have we just removed this special case from here (ie move this check to the callers that need it)?
I know that would be more disruptive, but it will also make increasing the internal precision easier later.
There was a problem hiding this comment.
There was a problem hiding this comment.
Oh, that's great. Moving from nSatoshisPerK to 1 was already and step forward. But I've strong reason to believe that this special case was the most important impediment for not being able to "easily" do more than *2 on internal precision in #7731(in fact, I don't think it would pass all the tests if I rebased this now due to this change).
If you create a PR to move the special case to the wallet only, please ping me for review, I am very interested in seeing that happening. Looking at the code you link to, it looks like that part can actually be simplified as a result, instead of complicating it. But tests will break...
|
After this, the following change will fail the new tests in amount_tests.cpp: 5ca2473 This is a mystery to me, can anybody help me understand? |
Currently negative fee rates are not supported on archs of 64-bit or more