lockunspent will now validate all of the provided outputs are both unspent and belong to the local wallet.
The operation is now also atomic.
Fix for #2667
1792 | @@ -1791,7 +1793,20 @@ Value lockunspent(const Array& params, bool fHelp) 1793 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); 1794 | 1795 | COutPoint outpt(uint256(txid), nOutput); 1796 | + if (!pwalletMain->IsLockableCoin(outpt)) { 1797 | + throw JSONRPCError(RPC_INVALID_PARAMETER, 1798 | + "Invalid parameter, expected unspent output belonging to this wallet");
Can you use 4-space indentation here also below throw please.
Does this change require any changes in the GUI coin-control code or do we directly benefit from this change?
Good question. At first read, it looks like the coin-control GUI could theoretically by-pass this new check and lock an unlockable coin. This could be confusing to an RPC user. eg. GUI user locks an unlockable coin, RPC user sees it in the output for listlockunspent and when they try to unlock it via lockunspent it fails due to the coin being unlockable.
But does the GUI allow it? I think it's pretty locked down in that regard, showing only coins that can be spent (and thus locked). But I may be wrong.
Havent tested, but I agree with @laanwj. You check 4 conditions (mapwallet output.n !ispent ismine), coin control calls AvailableCoins, checking the same but even more conditions. So it should never be possible to lock an unlockable coin in the GUI.
I also suggest:
This would be consistent with the GUI, checking the same conditions.
lockunspent will now validate all of the provided outputs are
both unspent and belong to the local wallet.
The operation is now also atomic.
@cozz I incorporated your feedback but note the semantic implication:
lockunspent lock=true for an already locked coin would now throw an error. lockunspent unlock=true for an already unlocked coin would now throw an error.
Previously, the behavior was:
lockunspent lock=true for an already locked coin returns true. lockunspent unlock=true for an already unlocked coin would return true.
I think a case could be made for either behavior but I want to point it out in case this violates a convention I'm unaware of. Or if it's particularly distasteful to anyone.
@aalness yes, maybe in the case "lockunspent lock=true for an already locked coin", show a different error message like "coin already locked". But throw an error is fine with me.
Code looks good, not sure what the core devs opinion is on this. So lets wait for another opinion here...
1084 | + return IsAvailableCoin(coin, output.hash, output.n, NULL); 1085 | +} 1086 | + 1087 | +bool CWallet::IsAvailableCoin(const CWalletTx& coin, uint256 hash, unsigned int n, const CCoinControl *coinControl) const 1088 | +{ 1089 | + // It's assumed the caller has tested coin.IsAvailable().
So now we have coin.IsAvailable as well as CWallet::IsAvailableCoin? I think that's a bit confusing.
@laanwj yes, so maybe not touch AvailableCoins at all. And just introduce 1 new function IsAvailableCoin, duplicating all the necessary logic. Just like IsLockableCoin before. Thats what I meant initially. Would also be easier to review and to compare. What do you think?
@laanwj yeah, that's fair. It bothered me slightly too, although, it seemed to be a bit of an existing convention to call a CWalletTx a "coin" or "pcoin". Do you think it would be less confusing to simply change the variable to "wtx"? Can you think of a better way to describe a transaction in this state, as opposed to "available"? Or would you just prefer that I remove the method altogether? @cozz I do like the property that IsAvailableCoin and AvailableCoins now share the same exact code. It seems like a stronger guarantee that the GUI and listunspent stay consistent with lockunspent.
Automatic sanity-testing: FAILED MERGE, see http://jenkins.bluematt.me/pull-tester/p3574_74ad5868245790c1f6c712c6afaa0d76398d2d7d/ for test log.
This pull does not merge cleanly onto current master This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/ Contact BlueMatt on freenode if something looks broken.
Closing this pull as it appears to be inactive. If you intend to resume working on this, let me know.