Opt-into-RBF for RPC & bitcoin-tx#9672
Conversation
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
rpc/rawtransaction.cpp:380:91: error: ‘fWalletRbf’ was not declared in this scopeThere was a problem hiding this comment.
I guess we don't really want -walletrbf to work on rawtx anyway. Fixed
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
This deleted line should be restored.
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
I think this if condition would be more readable if it were defined in terms of an "rbfOptOut" variable complementing the existing "rbfOptIn" variable above:
bool rbfOptIn = request.params.size() > 3 && request.params[3].isTrue();
bool rbfOptOut = request.params.size() > 3 && request.params[3].isFalse();
There was a problem hiding this comment.
This condition is being removed to check both options equally.
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Would be nice to exercise in an rpc test.
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Saying default=false is kind of misleading, because if you actually pass false instead of omitting this, it can cause the "Invalid parameter combination" error to trigger. Maybe:
(boolean, optional, default=null) Whether to signal that this transaction may be replaced by another with higher fees. If false, it is an error if any input specifies an incompatible sequence number.
There was a problem hiding this comment.
When sequences aren't provided, this value does decide them, and defaults to false. I'll combine the two...
src/wallet/wallet.cpp
Outdated
There was a problem hiding this comment.
You moved almost all the lines that mutate coinControl from FundTransaction to fundrawtransaction except for this one and the "coinControl.fAllowOtherInputs = true" line above. Any reason not to move these as well? This way the coin control object is fully initialized in one place and the argument can be const.
There was a problem hiding this comment.
That'd be doing too much at the caller side IMO.
There was a problem hiding this comment.
I'm confused by this as well. Can you expand a bit on why these particular members shouldn't be set by the caller?
src/wallet/rpcwallet.cpp
Outdated
src/bitcoin-tx.cpp
Outdated
There was a problem hiding this comment.
Unsigned int should be uint32_t.
Also, maybe this shouldn't overwrite sequence numbers if they already signal replacability, e.g.:
txin.nSequence = std::min(txin.nSequence, std::numeric_limits<uint32_t>::max() - 2)
| // and in the spirit of "smallest possible change from prior | ||
| // behavior." | ||
| bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf; | ||
| const uint32_t nSequence = rbf ? MAX_BIP125_RBF_SEQUENCE : (std::numeric_limits<unsigned int>::max() - 1); |
There was a problem hiding this comment.
Maybe change to <uint32_t> while you are here.
|
#9592 is merged now, so this would be good to rebase |
jnewbery
left a comment
There was a problem hiding this comment.
Needs rebase. A few nits in my review, but otherwise looks good.
You should add some test cases to /test/util/data to test the new functionality in bitcoin-tx
|
|
||
| def test_rpc(self): | ||
| us0 = self.nodes[0].listunspent()[0] | ||
| ins = [us0]; |
There was a problem hiding this comment.
suggest you combine this with the line above (and remove trailing semicolon):
ins = [self.nodes[0].listunspent()[0]]
| us0 = self.nodes[0].listunspent()[0] | ||
| ins = [us0]; | ||
| outs = {self.nodes[0].getnewaddress() : Decimal(1.0000000)} | ||
| rawtx0 = self.nodes[0].createrawtransaction(ins, outs, 0, True) |
There was a problem hiding this comment.
nit: perhaps you could use named arguments to make the it clear what 0, True and 0, False arguments do.
| rawtx1 = self.nodes[0].createrawtransaction(ins, outs, 0, False) | ||
| json0 = self.nodes[0].decoderawtransaction(rawtx0) | ||
| json1 = self.nodes[0].decoderawtransaction(rawtx1) | ||
| assert_equal(json0["vin"][0]["sequence"], 4294967293) |
There was a problem hiding this comment.
suggest you assert directly on the values rather than assign them to a throwaway local variable and assert immediately. eg:
assert_equal(self.nodes[0].decoderawtransaction(rawtx0)["vin"][0]["sequence"], 4294967293)
also, please add a comment explaining the magic 4294967293 and 4294967295 numbers (or better yet, define a MAX_BIP125_RBF_SEQUENCE constant)
| rawTx.nLockTime = nLockTime; | ||
| } | ||
|
|
||
| bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false; |
There was a problem hiding this comment.
This won't throw an error if the parameter isn't a bool (and silently set rbfOptIn to false).
Prefer to use get_bool() instead of isTrue() to throw an error when the caller accidentally uses a string "true" instead of a bool true.
|
|
||
| uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max()); | ||
| uint32_t nSequence; | ||
| if (rbfOptIn) { |
There was a problem hiding this comment.
nit: I think this would be clearer if it was an else if after the if (sequenceObj.isNum()) block
src/wallet/wallet.cpp
Outdated
There was a problem hiding this comment.
I'm confused by this as well. Can you expand a bit on why these particular members shouldn't be set by the caller?
| coinControl.destChange = CNoDestination(); | ||
| int changePosition = -1; | ||
| bool includeWatching = false; | ||
| coinControl.fAllowWatchOnly = false; // include watching |
There was a problem hiding this comment.
I don't think this comment adds any value.
| CFeeRate feeRate = CFeeRate(0); | ||
| bool overrideEstimatedFeerate = false; | ||
| coinControl.nFeeRate = CFeeRate(0); | ||
| coinControl.fOverrideFeeRate = false; |
There was a problem hiding this comment.
The coinControl constructor is already setting all of these members (in CCoinControl::SetNull()). Why are you setting them again here?
| // and in the spirit of "smallest possible change from prior | ||
| // behavior." | ||
| bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf; | ||
| const uint32_t nSequence = rbf ? MAX_BIP125_RBF_SEQUENCE : (std::numeric_limits<unsigned int>::max() - 1); |
There was a problem hiding this comment.
+1 for using MAX_BIP125_RBF_SEQUENCE instead of the magic subtraction you're replacing.
| * calling CreateTransaction(); | ||
| */ | ||
| bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey = true, const CTxDestination& destChange = CNoDestination()); | ||
| bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl, bool keepReserveKey = true); |
There was a problem hiding this comment.
nit: suggest you remove the unused default value for keepReserveKey
|
This needs rebase. The QT part is now in master. |
Yes, can we please try to move this forward? |
…vided with either value
|
Rebased |
|
utACK 9a5a1d7 |
9a5a1d7 RPC/rawtransaction: createrawtransaction: Check opt_into_rbf when provided with either value (Luke Dashjr) 23b0fe3 bitcoin-tx: rbfoptin: Avoid touching nSequence if the value is already opting in (Luke Dashjr) b005bf2 Introduce MAX_BIP125_RBF_SEQUENCE constant (Luke Dashjr) 575cde4 [bitcoin-tx] add rbfoptin command (Jonas Schnelli) 5d26244 [Tests] extend the replace-by-fee test to cover RPC rawtx features (Jonas Schnelli) 36bcab2 RPC/Wallet: Add RBF support for fundrawtransaction (Luke Dashjr) 891c5ee Wallet: Refactor FundTransaction to accept parameters via CCoinControl (Luke Dashjr) 578ec80 RPC: rawtransaction: Add RBF support for createrawtransaction (Luke Dashjr) Tree-SHA512: 446e37c617c188cc3b3fd1e2841c98eda6f4869e71cb3249c4a9e54002607d0f1e6bef92187f7894d4e0746ab449cfee89be9f6a1a8831e25c70cf912eac1570
|
huh? This only got a single untested ACK from the maintainer since a large rebase, yet it's already been merged. Most of my comments were nits, but I'm surprised this got merged in without tests covering the new functionality. This is essentially untested code at this point (either by reviewers or test cases). |
|
Code changes look good to me though. @ryanofsky also utACKed it. |
|
If so, I'm not sure whether to revert entirely or partially. |
|
post merge utACK 9a5a1d7. |
|
Just my 2 cents, but I don't see why this would be reverted. Personally, when I post suggestions on a PR, my only expectation is that the PR author will take a look at them and implement any that seem to be worthwhile. If the author didn't implement an idea I really liked, I would follow up with my own PR. If I had actual pressing feedback that I thought should hold up a merge, I'd accompany it with some kind of temporary NACK. |
|
OK - agreement on IRC and here is to not revert this, thanks everyone |
Rebase of #7159 on top of #9592