-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Show "bip125-replaceable" flag, when retrieving mempool entries #12676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
src/core_write.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo this should be the same key-value as the bip125-replaceable in the rpcwallet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! I updated the PR.
5d7cb0f to
e62c505
Compare
src/core_write.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignalsOptInRBF is not bip125-replacable.
- Confirmed transaction can never be replaced in the mempool
- Unconfirmed transactions that depend on a mempool-transaction that signals opt in rbf can be replaced
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you suggest to rename the flag to something like signals-rbf? Or rather do a stateful check, whether the transaction is actually replaceable, when the call is made?
The latter would probably be very useful, but given that TxToUniv isn't stateful and currently doesn't have any mempool relation, I don't see a straight forward way for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do this I'd say rename it to signals-rbf or such, which is also the name of the function already. And not make the raw transactions utility function decoding functionality depend on the mempool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which case I tend to Concept NACK. Just returning if the flag is set contradicts the bip125-replacability rules, which only adds confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to hijack.
I had considered adding a flag like this to the verbose output of getrawmempool. Assuming this idea were supported, based on your feedback @MarcoFalke - is it fair to say that you think it makes more sense to list a mempool transaction as replaceable (covering both explicit signaling and implicit based on ancestors) rather than just signals-rbf (just the explicit case)?
Do you think it would be appropriate to list that in getrawmempool?
e62c505 to
788885f
Compare
|
@conscott brought up the idea of adding the flag to mempool entries and mempool RPCs. I really like the idea, because these calls are actually mempool aware and provide full access to the mempool and thus also allow to check, whether a transaction is really replaceable instead of simply signaling replaceablity. I updated the PR accordingly, because I believe this is the way to go. @conscott if you want to submit this as PR, feel free to do so though, and I'll close this one. |
instagibbs
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/rpc/blockchain.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use brackets for multi-line conditionals
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, updated.
788885f to
eef1b43
Compare
|
re-ACK |
Sjors
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK eef1b43
test/functional/feature_rbf.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test for unknown?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.. this is going to be a bit difficult: the "unknown" case is only triggered, if the transaction isn't found in the mempool.
In the case of the RPCs this path might even get removed, given that we iterate over mempool entries, which are indeed in the mempool and thus never "unknown".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such a test might require mocking IsRBFOptIn in blockchain.cpp, but that seems overkill here.
src/rpc/blockchain.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can just be an assert(bfState != RBF_TRANSACTIONSTATE_UNKNOWN). Looking at rbf.cpp, the unknown state should only occur if the transaction in question is not found in the mempool, and this function only processes transactions that are currently in the mempool (with mempool lock held).
If the above is correct (I believe it is), the bip125-replaceable field can just become a boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of an assert here. It if it's really not possible, it's better to put the assert in rbf.cpp and remove this state from the enum. All this function should be concerned with is translating an enum to a string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually: what about a situation where a descendant is missing from the mempool (because it somehow got evicted)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have been more clear. In general it is possible to return RBF_TRANSACTIONSTATE_UNKNOWN from IsRBFOptIn(), however this call stack in particular (all mempool related rpc's) only calls IsRBFOptIn() on transactions we know to be in the mempool. So, the assert would belong here, not in rfb.cpp. I understand this still may not be the best option, I just wanted to make my language clear since my comment above was a bit ambiguous.
I am not sure I understand the problem/situation where 'a descendant is missing from the mempool'. Can you elaborate please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of using assert in non-consensus critical code, given it's massive impact, if it's hit (e.g. by accident in the future etc.).
In the case of the RPCs "unknown" isn't triggered, because they iterate over mempool entries, which are inherently part of the mempool, but I kind of tend to leave it there for the potential case entryToJSON() is called in a different context. I'd be fine with removing this path though, too.
Actually: what about a situation where a descendant is missing from the mempool (because it somehow got evicted)?
Not an issue as far as I can see. We only care about ancestors and whether an unconfirmed ancestor signals RBF, which makes the chain replaceable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mempool.dat is sorted in dependency order, so ancestors always appear earlier. Further, the mempool is at all times internally consistent (when observable): all mempool transactions either spend a transaction output from the chainstate (so from a confirmed transaction), or another mempool output. There are also never any double spends in the mempool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any opinion on listing unknown state @MarcoFalke ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong opinion if the value of 'bip125-replacable' should be string (yes/no/unknown) or bool.
It seems entryToJSON can only be called when the entry is in the mempool (c.f. mempool.vTxHashes[e.vTxHashesIdx].first.ToString()). Thus, we can surely determine if it is replacable.
Instead of adding an assert, I'd prefer to throw some json exception that mentions that it never can be thrown.
I guess you could throw it in entryToJSON to make sure it is passed up to all potential callers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But does entryToJSON really care, whether it's in the mempool or not? I think this limits it's functionality in some way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
entryToJSON specifically processes mempool transactions (CTxMemPoolEntry &e) - and I don't believe you should be able to have a CTxMemPoolEntry reference for something not currently in the mempool (it should guarantees this consistency), so in that sense, entryToJson should never be called in a "different context" (where the tx is not in mempool).
Anyhow, I am not trying to get pedantic on this point. I want this change (and requested it) and I am okay with the current implementation.
|
Concept ACK. Thanks for updating @dexX7 - just left a comment about the unknown state. Will test this out tomorrow. |
|
Regarding checking the |
|
Concept ACK |
conscott
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test ACK eef1b43b5860122bd7dc9270b5b5ba3f64b1dc0e
|
Hey guys, just to clarify: given there were mixed reactions, do you insist on removing the branch for the "unknown" case and replace it with an exception or is this PR good to go as it is? |
|
@dexX7 - I was arguing over the |
|
I just fail to see why it makes sense to burden rpc users with a third value that is never actually set. |
eef1b43 to
5434aaa
Compare
|
Alright, updated. :) |
src/rpc/blockchain.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to encode a bool into a string, imo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
e332b37 to
56301e0
Compare
This affects getrawmempool, getmempoolentry, getmempoolancestors and getmempooldescendants.
56301e0 to
dc6f7eb
Compare
dc6f7eb to
870bd4c
Compare
| bool rbfStatus = false; | ||
| RBFTransactionState rbfState = IsRBFOptIn(tx, mempool); | ||
| if (rbfState == RBFTransactionState::UNKNOWN) { | ||
| throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throwing here seems nasty. Just don't add a key?
Eg:
switch (IsRBFOptIn(tx, mempool)) {
case RBFTransactionState::FINAL:
info.push_back(Pair("bip125-replaceable", false));
break;
case RBFTransactionState::REPLACEABLE_BIP125:
info.push_back(Pair("bip125-replaceable", true));
break;
case RBFTransactionState::UNKNOWN:
break;
}(Doing it this way also gets a compile-time warning if a new state is added later)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be nice to have this produce the same output as the wallet rpc calls that provide the same information (which appears to be "yes"/"no"/"unknown").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is even possible to hit this case since it requires the transaction to not be in the mempool (for the unknown state) yet every entry we are processing here comes from the mempool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @achow101
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @sdaftuar
|
utACK 870bd4c |
|
utACK 870bd4c |
| The last travis run for this pull request was 61 days ago and is thus outdated. To trigger a fresh travis build, this pull request should be closed and re-opened. |
|
This seems mergeable, should do so after 0.17 branch as this is a feature |
… entries 870bd4c Update functional RBF test to check replaceable flag (dexX7) 820d31f Add "bip125-replaceable" flag to mempool RPCs (dexX7) Pull request description: This pull request adds a flag "bip125-replaceable" to the mempool RPCs getrawmempool, getmempoolentry, getmempoolancestors and getmempooldescendants, which indicates whether an unconfirmed transaction might be replaced. Initially the flag was added to the raw transaction RPCs, but thanks to @conscott, it was moved to the mempool RPCs, which actually have access to the mempool. ~~This pull request adds a flag "bip125-replaceable" to the RPCs "getrawtransaction" and "decoderawtransaction", which indicates, whether a transaction signals BIP 125 replaceability.~~ There was some discussion in #7817, whether showing replaceability in the UI could lead to the false assumption that transactions that don't signal BIP 125 are truely non-replaceable, but given that this PR tackles the raw transaction interface, which is a rather low level tool, I believe having this extra piece of information isn't bad. Tree-SHA512: 1f5511957af2c20a9a6c79d80a335c3be37a2402dbf829c40cceaa01a24868eab81a9c1cdb0b3d77198fa3bb82799e3540a5c0ce7f35bbac80d73f7133ff7cbc
This pull request adds a flag "bip125-replaceable" to the mempool RPCs getrawmempool, getmempoolentry, getmempoolancestors and getmempooldescendants, which indicates whether an unconfirmed transaction might be replaced.
Initially the flag was added to the raw transaction RPCs, but thanks to @conscott, it was moved to the mempool RPCs, which actually have access to the mempool.
This pull request adds a flag "bip125-replaceable" to the RPCs "getrawtransaction" and "decoderawtransaction", which indicates, whether a transaction signals BIP 125 replaceability.There was some discussion in #7817, whether showing replaceability in the UI could lead to the false assumption that transactions that don't signal BIP 125 are truely non-replaceable, but given that this PR tackles the raw transaction interface, which is a rather low level tool, I believe having this extra piece of information isn't bad.