Add P2SH-P2WSH support to signrawtransaction and listunspent RPC#11708
Add P2SH-P2WSH support to signrawtransaction and listunspent RPC#11708meshcollider wants to merge 5 commits intobitcoin:masterfrom meshcollider:201711_signrawtransaction_wsh
Conversation
|
NACK, redeemScript + scriptPubKey are sufficient information to know whether you are talking about P2SH-P2WSH, P2SH, P2WSH. Having one more "witness script" is just redundant information which can go wrong. If you enter the witness script in "redeemScript" field, you can easily find out in code if it mean P2SH or Witness by comparing with the scriptPubKey, there is no ambiguity. |
|
@NicolasDorier How so? The redeemscript only contains a hash of the witness script in the case of P2SH-P2WSH, which is not sufficient to sign with. It would be possible to require passing only the witness script, and automatically also add the v0 P2WSH redeemscript (and any future versions?). But just the redeemscript is not enough. |
|
Indeed, IMO its much cleaner implementation and user experience to have the witnessScript provided in addition to the redeemScript, not only because that avoids the ambiguous witness version issue in a nice way but also because then it is clear to the user which script the redeemScript actually refers to (because the redeemScript output of other RPCs in general would refer to the wrapper P2SH redeemScript not the witnessScript which would introduce confusion). |
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Watch out with the indentation,... the \" result in one char. It may look unaligned in the source code but is aligned in the help output.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
nit: replace 32 with sizeof()?
|
Concept ACK. Can you add a test? |
|
@jonasschnelli yep will do, see TODO section :) Just trying to work out the cleanest way to test it wrt all the existing tests in segwit.py |
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
nit: the whash.size() should also go here... :P
There was a problem hiding this comment.
Heh missed that, thanks :P
|
Test and release notes added, @jonasschnelli's nits addresses |
|
This is how I am doing with NBitcoin for long. @sipa if you have If If If You can then Hash(Hash(redeemScript)) and verify that it is indeed into You can derive the P2SH redeem from the Segwit redeem, so no need to specify both. Again, strong NACK on this one. This is not needed. |
|
@NicolasDorier Ah, I'm using redeemscript exclusively for P2SH. Yes, if you have the witness script, and can correctly guess it is a V0 P2WSH embedded in P2SH, you can derive the redeemscript. I'm not convinced guessing is the best approach. |
|
Well the thing is that this field is called If you insist having both redeem, then I would suggest to rename But then, the logic of this RPC method will need to ensure that all, I am convinced specifying both is just wrong as there is no ambiguity, no way to guess incorrectly. Just more way for the user to get wrong and confused, and more code to ensure everything is coherent on both side. |
|
@NicolasDorier That's the fair point, the naming would be inconsistent in that case. We also don't actually need to distinguish for our implementation. @meshcollider perhaps we can just permit redeemScript to be a list, in which case multiple scripts gets loaded with AddCScript? |
|
Yep I'm happy with that approach too, I just definitely want to avoid guessing the witness version as mentioned. Although re: terminology, I've only ever seen redeemScript used to refer exclusively to P2SH, even the bitcoincore.org segwit wallet dev guide refers to the witness redeem script as witnessScript only. |
|
The fact that "redeemScript" can refer to all type of PS2SH*-P2WSH* redeems makes migration from P2SH to Segwit easier, as there is no additional fields to pass around that did not existed before. In NBitcoin, there is a type called That said I would be fine with redeemScript being an array as well. |
|
I've made the modification to include the witnessScript in a redeem script array in the case of P2SH-P2WSH, will squash those modification commits if that approach is acceptable |
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
you are not using that anymore
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
you are not using that anymore
|
Fixed, thanks @NicolasDorier |
There was a problem hiding this comment.
nit: check if the redeemScript[0] is the p2sh redeem.
|
Code review ACK |
|
Rebased and added the extra check as suggested by @NicolasDorier. That also fixed the unused OP_0 warning. |
|
reACK |
|
Should passing a redeem script array to signrawtransaction be possible with bitcoin-cli? It looks this might not work currently because the param does not have an entry in vRPCConvertParams. You might be able to work around this with something like: if (redeem_script.isStr() && !IsHex(redeem_script.get_str())) {
redeem_script.read(redeem_script.get_str().substr());
RPCTypeCheckArgument(redeem_script, UniValue::VARR);
} |
ryanofsky
left a comment
There was a problem hiding this comment.
utACK a1dec739839053ce095f84ea1d281744124896e6
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Not directly related to this PR, but seems like it might good to return an error if this condition is false instead of skipping validation of the redeemscript parameter.
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Maybe drop this line. It prevents get_str() below from throwing an exception if the wrong type is passed.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
It might be good to explicitly say this will be an array for p2wsh and nested p2wsh outputs, a string for traditional p2sh outputs, and unset in other cases.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
IIUC, this should never be false? Would be helpful to have a comment saying this, or else mentioning when it would be expected.
|
This PR has two code review acks (from me and NicolasDorier) so maybe it is close to being merged. The remaining comments that haven't been responded to are minor and shouldn't hold this up. |
|
Addressed @ryanofsky feedback, thanks! |
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Missing error when not string or array? Suggestion (scripts is a vector of strings):
if (rs.getType() == UniValue::VARR) {
for (auto r : rs.getValues()) {
scripts.push_back(r.get_str());
}
} else {
scripts.push_back(rs.get_str());
}There was a problem hiding this comment.
Nice idea, done, thanks :)
|
Feedback addressed, fixup commits squashed into one cleanup commit |
test/functional/rawtransactions.py
Outdated
There was a problem hiding this comment.
This redeemScript parameter was being silently ignored until now, because scripts are not used by signrawtransaction if no keys are passed in (the internal wallet is used instead). New code returns an error instead of silently ignoring it, so it was removed.
ryanofsky
left a comment
There was a problem hiding this comment.
utACK 50074643f20cc36e6ffbbec22f1c850c6e9a3207. Only change since last review is the new cleanup commit. Feel free to ignore very minor review suggestions below.
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Could use const reference to avoid string copy here (though there are more copies below anyway).
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Could use const auto& to avoid univalue copies
src/rpc/rawtransaction.cpp
Outdated
There was a problem hiding this comment.
Maybe s/should not accept/don't currently support accepting/. This seems more like a reasonable limitation of the current implementation than a desirable feature of it.
|
Fixed @ryanofsky's comments, thanks :) Haven't tested CLI yet though |
ryanofsky
left a comment
There was a problem hiding this comment.
utACK 22397a43a6601e76582053dc95381196f520a610. Sorry for the delay, only changes since last review were the suggested comment & for loop tweaks.
|
Rebased to fix merge conflict in rawtransactions.py |
ryanofsky
left a comment
There was a problem hiding this comment.
utACK 73b582dc6624ffc27dc65cf7f60e6ff8829b6691. No changes since last review except for rebase and simple conflict resolution in rawtransactions.py.
|
Concept ACK. Rebase/squash last commit? |
|
@sipa done :) |
5f605e1 Make signrawtransaction accept P2SH-P2WSH redeemscripts (Pieter Wuille) Pull request description: This is a quick fix for #12418, which is a regression in 0.16. It permits specifying just the inner redeemscript to let `signrawtransaction` succeed. This inner redeemscript is already reported by `addmultisigaddress` & co. #11708 uses a different approach, where `listunspent` reports both inner & outer redeemscript, but requires both to be provided to `signrawtransaction`. Part of #11708 is still needed even in combination with this PR however, as currently the inner redeemscript isn't reported by `listunspent`. Tree-SHA512: a6fa2b2661ce04db25cf029dd31da39c0b4811d43692f816dfe0f77b4159b5e2952051664356a579f690ccd58a626e0975708afcd7ad5919366c490944e3a9a5
| if (pwallet->GetCScript(id, witnessScript)) { | ||
| scripts.push_back(HexStr(witnessScript.begin(), witnessScript.end())); | ||
| } | ||
| entry.push_back(Pair("redeemScript", scripts)); |
There was a problem hiding this comment.
IIRC, Pair push_backs were just cleaned up... :/
There was a problem hiding this comment.
Yes, this needs a large rebase and cleanup anyway now signrawtransaction was split up, things like this will be done at the same time when I get onto this
|
|
||
| - The `listunspent` output will now return an array of scripts as the `redeemScript` in the case of P2SH-P2WSH, | ||
| for compatibility with the `signrawtransaction` change above. In other cases, `listunspent` will continue to return | ||
| the only `redeemScript` as a string, as before. |
There was a problem hiding this comment.
Is there a reason to break the API here? Why not add a new key for the witnessScript?
There was a problem hiding this comment.
The API only breaks in the case of P2SH-P2WSH which was not supported at all before anyway. Adding a new key for witnessScript to listunspent would make its output incompatible with the signrawtransaction input which expects a list of scripts in this case
|
Needs rebase |
| UniValue rs = find_value(prevOut, "redeemScript"); | ||
| if (rs.getType() != UniValue::VNULL) { | ||
| if (!(scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash())) { | ||
| // if this isnt P2SH or P2WSH, scripts should not be provided |
There was a problem hiding this comment.
Typo found by codespell: “isnt” should be “isn’t” or “is not” :-)
|
Closing this, replaced by #14481 |
6ca836a Add release note for listunspent P2WSH change (MeshCollider) 928beae Add test for P2SH-P2WSH in signrawtransactionwithkey and listunspent (MeshCollider) 314784a Make listunspent and signrawtransaction RPCs support witnessScript (MeshCollider) Pull request description: This is a reworked version of #11708 after #12427 and the `signrawtransaction` split. For a P2WSH address, listunspent should return the witness script, and for a P2SH-P2WSH address, it should also return the inner witness script (because SignTransaction will automatically wrap it in P2SH if required). Includes a test which also tests the behaviour of #12427, and release note. Tree-SHA512: a8e72cf16930312bf48ec47e44a68f8d7e26664043c1b4cc0983eb25aec4087e511188ff9a0f181cd7b8a0c068c60d7f1e7e3f226b79e8c48890039dcf57f7b7
Currently
signrawtransactionworks with P2SH-P2WSH which are already in wallet (e.g.addmultisigaddress->addwitnessaddress). But when using signrawtransaction with keys which aren't in the wallet, there is currently only aredeemScriptkey so you cannot enter both the P2SH redeemScript and the witness script. There is an undocumented workaround by including the same input twice (suggested on StackExchange here), once with each script, but that is unnecessary and hacky.This simply allows the optional inclusion of a witnessScript key in the JSON input to
signrawtransaction. Because it uses JSON, this is a non-breaking change.Also, as discussed on IRC (see here), we add a
witnessScriptoutput to the listunspent RPC for P2SH-P2WSH addresses because gmaxwell pointed out signrawtransaction should be able to get most of the needed info from listunspent.Closes #11693
TODO:
Needs tests + release notes