Skip to content
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

Add SegWit support to importmulti #14454

Merged
merged 5 commits into from Oct 31, 2018
Merged

Add SegWit support to importmulti #14454

merged 5 commits into from Oct 31, 2018

Conversation

meshcollider
Copy link
Contributor

@meshcollider meshcollider commented Oct 10, 2018

Add support for segwit to importmulti, supports P2WSH, P2WPKH, P2SH-P2WPKH, P2SH-P2WSH. Adds a new witnessscript parameter which must be used for the witness scripts in the relevant situations.

Also includes some tests for the various import types.

Also makes the change in #14019 redundant, but cherry-picks the test from that PR to test the behavior (@achow101).

Fixes #12253, also addresses the second point in #12703, and fixes #14407

@DrahtBot
Copy link
Contributor

DrahtBot commented Oct 10, 2018

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.


CTxDestination pubkey_dest = pubKey.GetID();
CTxDestination pubkey_dest = pubKey.GetID();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed?

if (pubKeys.size() && keys.size() == 0) {
const std::string& strPubKey = pubKeys[0].get_str();
// Generate the scripts
std::vector<unsigned char> vData(ParseHex(strWitnessScript));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use another variable name to avoid shadowing existing local variable vData :-)

@meshcollider
Copy link
Contributor Author

Thanks for reviewing @practicalswift, both comments addressed :)

Copy link
Member

@achow101 achow101 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

59f8e547130fc1cb756da7d990f65445ca196f5f could be squashed into 24092b3402693d8a2c39b640db18748b168863e9

acdba74ee011bfcafc9f28b528918815b1de4920 seems to be an unrelated change

if (isP2SH && !IsHex(strRedeemScript)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script");
// Force users to provide the witness script in its field rather than redeemscript
if (!strRedeemScript.empty() && script.IsPayToWitnessScriptHash()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of checking that strRedeemScript is not empty, this should check that strWitnessScript is empty. Or it could check both: !strRedeemScript.empty() && strWitnessScript.empty().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to provide a P2WSH scriptPubKey without providing the witness script for it, e.g. watch only, so I don't think that's right

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think checking both covers that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking both would mean that if witnessScript and redeemScript were both present, it would allow it, which makes no sense if its not a P2WSH address

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2WSH scriptPubKey without providing the witness script for it, e.g. watch only

Do we already support that? And test it? If not, maybe it's easier to just treat it as P2SH until we know the witnessScript.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sjors Yes, of course, just importaddress it. It probably works fine without this PR even.

Copy link
Member

@Sjors Sjors Oct 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sipa so we currently support importing a 3... address as watch-only, but the wallet doesn't know or care if it's SegWit or not. The new code here is for a scenario where you do know it's SegWit script.IsPayToWitnessScriptHash(), which means you know the strRedeemScript, but you don't know the strWitnessScript. That seems a strange situation. Why would anyone give you the legacy redeem script but not the Segwit witness script?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sjors I have no idea what you're talking about. This is about the case where you're importing a bech32 P2WSH address (no P2SH), without revealing the script inside - which is a totally reasonable thing if you don't care about solvability.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sipa I see, I may have gotten confused because Github is showing if (isP2SH && !IsHex(strRedeemScript as the deleted line, but this thread is about an earlier code branch.
schermafbeelding 2018-10-22 om 14 16 57

// Import redeem script.
std::vector<unsigned char> vData(ParseHex(strRedeemScript));
CScript redeemScript = CScript(vData.begin(), vData.end());
CScriptID redeem_id(redeemScript);
CScript redeemDestination = GetScriptForDestination(redeem_id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: snake_case


// Optional fields.
const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
const std::string& strWitnessScript = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: snake_case

const std::string& strPubKey = pubKeys[0].get_str();
// Generate the scripts
std::vector<unsigned char> vData(ParseHex(strWitnessScript));
CScript witnessScript = CScript(vData.begin(), vData.end());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: snake_case

std::vector<unsigned char> vData(ParseHex(strWitnessScript));
CScript witnessScript = CScript(vData.begin(), vData.end());
CScriptID witness_id(witnessScript);
CScript witnessDestination = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: snake_case

// P2PK/P2PKH/P2WPKH
} else if (dest.type() == typeid(CKeyID) || dest.type() == typeid(WitnessV0KeyHash)) {
if (keys.size() > 1 || pubKeys.size() > 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error wouldn't make sense if only pubkeys were given.

}
pubkey = pubkey_temp;
}
if (pubkey.size()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of checking pubkey size, check validity? (e.g. use IsValid() or IsFullyValid())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsValid() just performs the same size check anyway, but yep I'll do that for the sake of clarity, I don't think we need an IsFullyValid() check here

@meshcollider
Copy link
Contributor Author

Thanks @achow101, addressed all your points

@sipa
Copy link
Member

sipa commented Oct 15, 2018

@meshcollider I don't think it's necessary to import the pubkeys involved separately anymore since #14424, and in fact that sounds very dangerous (you could be tricked into importing a 2-of-3 multisig where you have 2 of the keys, but then receiving a payment to a P2PKH of the third key, and seeing it treated towards your watch-only balance). NACK until that is fixed (or at least restricted to not have that issue, but I believe that rebasing on 14424 will be sufficient).

@meshcollider
Copy link
Contributor Author

meshcollider commented Oct 16, 2018

@sipa good point, fixed, and rebased on master to include the public key fix

@sipa
Copy link
Member

sipa commented Oct 17, 2018

I think there are a few things that need fixing:

  • There doesn't seem to be code for P2SH-P2WPKH (which matters at least when passing in a pubkey in that case, which won't be imported).
  • The added tests only cover whether importmulti returns true, not whether it actually imported anything.
  • The added tests are restricted to watchonly and spendable cases, but no solvable-but-not-spendable ones.

@meshcollider
Copy link
Contributor Author

I believe I've addressed the points, thanks for the feedback so far

Copy link
Member

@sipa sipa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

}

// Import private keys.
// P2PK/P2PKH/P2WPKH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may make sense to repeat the trick from the P2SH block of 'descending' into scriptPubKey/address of the redeemscript, to the P2WSH block, and then do P2PK/P2PKH/P2WPKH as a totally new case rather than an else branch. This would make the code work correctly for P2PK/P2PKH nested inside P2WSH (maybe track that you don't permit P2WPKH inside P2WSH though).

@@ -458,6 +468,74 @@ def run_test (self):
"timestamp": "",
}])

# Import P2WPKH address
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a number more scenarios that make sense to test, I think:

  • Address based import (without key/script) of P2WSH-multisig
  • For all of P2WPKH, P2WSH-multisig, P2SH-P2WPKH, P2SH-P2WSH-multisig, versions with script/pubkey but no private key, and test that the result is solvable.
  • P2WPKH with private key, result must be spendable (not just watchonly)
  • P2WSH-multisig and P2SH-multisig with more than 1 key, where some of the keys are specified as private keys, and some as public keys.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re "Address based import", should this result in the following?

  "ismine": false,
  "iswatchonly": true,
  "issolvable": false,
  "isscript": true,
  "iswitness": true,
  "witness_version": 0

Re "must be spendable", this means "ismine": true and "iswatchonly": false?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sjors Correct.

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK.

I tested 65ecf2d importing a watch-only bech32 address, which worked.

I also tested importing a watch-only p2sh-p2wpkh address like so: importmulti '[{"scriptPubKey": {"address": "2NFiDQiCdRYaRUdWMerff1qSTR4EC7zSBmB"}, "timestamp": "now", "pubkeys": ["03f33112792b07e9994933287ea71069d94176225f745822e47151d39e754d957f"]}]'. This is considered "issolvable": false. Once I add the private key it does know how to solve it.

Code looks good to me, but I don't pretend to understand all the edge cases involved. The tests really help illustrate it, so the more the better, see Sipa's suggestions:
480cba3#r225796932)

// Should have script or JSON with "address".
if (!(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address")) && !(scriptPubKey.getType() == UniValue::VSTR)) {
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how the code suggestion feature works. I suspect it creates a new commit, in which case it's better to just copy-paste the text and amend an existing commit.

@@ -858,32 +853,31 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between watchonly and keys");
}

// Internal + Label
// Internal addresses should not have a label
if (internal && data.exists("label")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest using the same error message as the above comment: Internal addresses should not have a label

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also get a test for this?

if (isP2SH && !IsHex(strRedeemScript)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script");
// Force users to provide the witness script in its field rather than redeemscript
if (!strRedeemScript.empty() && script.IsPayToWitnessScriptHash()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2WSH scriptPubKey without providing the witness script for it, e.g. watch only

Do we already support that? And test it? If not, maybe it's easier to just treat it as P2SH until we know the witnessScript.

@@ -809,29 +809,24 @@ UniValue dumpwallet(const JSONRPCRequest& request)
static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move this function to a different file? Unless dump means dumping ground :-)

I understand if you prefer to keep this PR simple though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's specific to importing things, though, which is the scope of rpcdump.cpp?

@@ -458,6 +468,74 @@ def run_test (self):
"timestamp": "",
}])

# Import P2WPKH address
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re "Address based import", should this result in the following?

  "ismine": false,
  "iswatchonly": true,
  "issolvable": false,
  "isscript": true,
  "iswitness": true,
  "witness_version": 0

Re "must be spendable", this means "ismine": true and "iswatchonly": false?

// Should have script or JSON with "address".
if (!(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address")) && !(scriptPubKey.getType() == UniValue::VSTR)) {
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good time to give a more descriptive error?

@@ -858,32 +853,31 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between watchonly and keys");
}

// Internal + Label
// Internal addresses should not have a label
if (internal && data.exists("label")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also get a test for this?

throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
// Force users to provide the witness script in its field rather than redeemscript
if (!strRedeemScript.empty() && script.IsPayToWitnessScriptHash()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Provide witnessscript not redeemscript for P2WSH address");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wording suggestion: "P2WSH addresses have an empty redeemscript. Please provide the witnessscript instead."

if (!strRedeemScript.empty() && script.IsPayToScriptHash()) {
// Check the redeemScript is valid
if (!IsHex(strRedeemScript)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: "Invalid redeem script: must be hex string"

throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
}
const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while we're here could we rename this to something more self-documenting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@instagibbs what do you suggest? script_or_address?

if (!pwallet->HaveCScript(redeem_id) && !pwallet->AddCScript(redeemScript)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}

CScript redeemDestination = GetScriptForDestination(redeem_id);
// Check for P2SH-P2WSH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this is a transient commit, but could there be a TODO P2SH-P2WPKH comment somewhere around here?

CKeyID vchAddress = pubkey.GetID();
pwallet->MarkDirty();
pwallet->SetAddressBook(vchAddress, label, "receive");
// P2WSH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// (P2SH-)P2WSH

Makes it more clear to me that the above block changed the script

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And same thing with: // P2PK/P2PKH/P2WPKH

}

// Process. //
CScript original_script = script;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scriptpubkey_script more self-explanatory? "original" is context dependent.


// Process. //
CScript original_script = script;
CTxDestination original_dest = dest;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scriptpubkey_dest more self-explanatory? "original" is context dependent.

@meshcollider
Copy link
Contributor Author

All comments so far are addressed, lots more tests added. Thanks @sipa, @instagibbs, @Sjors

@Sjors
Copy link
Member

Sjors commented Oct 18, 2018

@meshcollider I'm still seeing the same behavior I described above when importing a p2sh-p2wpkh address using just the address and public key.

@sipa
Copy link
Member

sipa commented Oct 18, 2018

@Sjors You need the redeemscript to make your example solvable (otherwise there is no way for the matcher to go from a P2SH hash to knowing what script the hash is of).

With the private key the weird-evil-but-necessary magic behaviour that causes us to automatically recognize P2WPKH and P2SH-P2WPKH payments to known private keys triggers.

@Sjors
Copy link
Member

Sjors commented Oct 18, 2018

Your wording suggests you're not a fan of adding that weird-evil-but-optional magic behavior to the (very common) case of having one public key?

@meshcollider
Copy link
Contributor Author

@Sjors I'm not really a fan of it, this code is already edge-cased enough without adding more ifs to test for, but I'm happy to add it if you really think its worthwhile.

@sipa
Copy link
Member

sipa commented Oct 18, 2018

@Sjors No, but I have suggested something else before, which would perhaps also solve your issue, namely that for all single-key schemes you can just provide the pubkey, and importmulti would automatically try the different schemes to see which matches your address/script.

At the very least, something for another PR, though.

@meshcollider
Copy link
Contributor Author

And such a case would be so easy with descriptors too ;)

@Sjors
Copy link
Member

Sjors commented Oct 18, 2018

I'm fine with focusing on descriptors, since those are an order of magnitude more intuitive than the current importmulti syntax.

@DrahtBot DrahtBot mentioned this pull request Oct 20, 2018
@meshcollider
Copy link
Contributor Author

Comments addressed + squashed some commits together

if (IsValidDestination(dest)) {
pwallet->SetAddressBook(dest, label, "receive");
// Import into the wallet
if (!pwallet->AddWatchOnly(witness_script, timestamp)) {
Copy link
Member

@sipa sipa Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small issue still: for P2SH-P2WSH it's unnecessary (and undesirable, I think) to also import the inner P2WSH script as watch-only.

It's not necessary because we're already marking the P2SH-P2WSH script as watch-only, and for solvability all we need is AddCScript, not AddWatchOnly.

It's undesirable because it will cause us to treat payments to the P2WSH address as watchonly IsMine (instead of just the P2SH-P2WSH version).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, fixed

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a few more questions inline, hopefully merely to reduce my own confusion.

My above concerns are addressed in e4a66bb, modulo two tests that @sipa requested and are either missing or I overlooked them.

The added tests only cover whether importmulti returns true, not whether it actually imported anything.

This is done now by checking properties via getaddressinfo.

The added tests are restricted to watchonly and spendable cases, but no solvable-but-not-spendable ones.

Some of the ['solvable'], True) tests now check that ['ismine'], False, but none check for iswatchonly'],False].

Address based import (without key/script) of P2WSH-multisig

Covered in # P2WSH multisig address without scripts or keys and # P2SH-P2WSH 1-of-1 multisig + redeemscript with no private key

For all of P2WPKH, P2WSH-multisig, P2SH-P2WPKH, P2SH-P2WSH-multisig, versions with script/pubkey but no private key, and test that the result is solvable.

I think this one is still missing for P2WSH multisig, between the # P2WSH multisig address without scripts or keys and # Same P2WSH multisig address as above, but now with witnessscript + private keys tests?

P2WPKH with private key, result must be spendable (not just watchonly)

Where "spendable" means ("ismine": true and "iswatchonly": false). This is done.

P2WSH-multisig and P2SH-multisig with more than 1 key, where some of the keys are specified as private keys, and some as public keys.

Missing?

I made a commit that checks solvable for all legacy scenarios as well: Sjors@02d553b

assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['solvable'], False)
Copy link
Member

@Sjors Sjors Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sipa can you remind me why a Native Pay-to-Witness-Public-Key-Hash isn't solvable, even though legacy Pay-to-Public-Key-Hash addresses are? Is that just to reduce evil magic like in the P2SH-P2PKH case?
If so, maybe add a comment in the test or in the RPC doc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this example it's not solvable because the public key isn't included. It has nothing to do with the script/witness hashing type.

In general, solvability is very easy. Start at the scriptPubKey. Whenever it includes a script hash, we must receive the actual script, and recurse into it. Whenever you encounter a pubkey hash, we must receive the actual public key. A scriptPubKey is solvable whenever you can descend all the way to scripts and pubkeys without any hashes of unknown things.

The only exception to that is that whenever you have a private key X, we also automatically import the P2WPKH and P2SH-P2WPKH versions of it, so no separate importing is needed in that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this example it's not solvable because the public key isn't included.

OK, that makes sense. Actually I misread the legacy test: it does add the public key, which why it's solvable.

@sipa
Copy link
Member

sipa commented Oct 23, 2018

utACK e4a66bb. As @Sjors points out there are some combinations for which tests can be added, but I think that can be done later.

Please squash fixups?

@meshcollider
Copy link
Contributor Author

meshcollider commented Oct 24, 2018

Squashed fixups into their respective commits, thanks for the review :)

@sipa
Copy link
Member

sipa commented Oct 25, 2018

utACK c11875c

Copy link
Member

@instagibbs instagibbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK

}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].getaddressinfo(multi_sig_script['address'])
assert_equal(address_assert['solvable'], False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if "sigsrequired" and "ismine" aren't in results can we assert their absence here?

}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].getaddressinfo(multi_sig_script['address'])
assert_equal(address_assert['solvable'], True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ismine?

@@ -3538,6 +3538,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" \"address\" : \"address\", (string) The bitcoin address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex-encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"solvable\" : true|false, (boolean) If the address is solvable by the wallet\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could have release note.

pwallet->UpdateTimeFirstKey(timestamp);
}
// (P2SH-)P2PK/P2PKH/P2WPKH
if (dest.type() == typeid(CKeyID) || dest.type() == typeid(WitnessV0KeyHash)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First time using RTTI? Maybe it could be avoided?

BTW, didn't test but I don't see variant::type() in boost 1.47 documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@promag it seems to be there: https://www.boost.org/doc/libs/1_47_0/doc/html/boost/variant.html
I could also do dest.which() == 1 || dest.which() == 4 but that's very unclear, or define a new enum of the types, but that seemed over the top unless there's a good reason to avoid RTTI?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it's in 1.47. Anyway this is removed in #14565.

@achow101
Copy link
Member

utACK 201451b

@laanwj
Copy link
Member

laanwj commented Oct 31, 2018

looks good to me, adding the solvable to getaddressinfo makes a lot of sense, and tests also look good to me
utACK c11875c

@laanwj laanwj merged commit c11875c into bitcoin:master Oct 31, 2018
laanwj added a commit that referenced this pull request Oct 31, 2018
c11875c Add segwit address tests for importmulti (MeshCollider)
201451b Make getaddressinfo return solvability (MeshCollider)
1753d21 Add release notes for importmulti segwit change (MeshCollider)
353c064 Fix typo in test_framework/blocktools (MeshCollider)
f6ed748 Add SegWit support to importmulti with some ProcessImport cleanup (MeshCollider)

Pull request description:

  Add support for segwit to importmulti, supports P2WSH, P2WPKH, P2SH-P2WPKH, P2SH-P2WSH. Adds a new `witnessscript` parameter which must be used for the witness scripts in the relevant situations.

  Also includes some tests for the various import types.

  ~Also makes the change in #14019 redundant, but cherry-picks the test from that PR to test the behavior (@achow101).~

  Fixes #12253, also addresses the second point in #12703, and fixes #14407

Tree-SHA512: 775a755c524d1c387a99acddd772f677d2073876b72403dcfb92c59f9b405ae13ceedcf4dbd2ee1d7a8db91c494f67ca137161032ee3a2071282eeb411be090a
@meshcollider meshcollider deleted the 201810_importmulti_segwit_support branch October 31, 2018 21:40
@laanwj laanwj removed this from Blockers in High-priority for review Nov 1, 2018
laanwj added a commit that referenced this pull request Feb 7, 2019
b985e9c Add release notes for importmulti descriptor support (MeshCollider)
fbb5e93 Add test for importing via descriptor (MeshCollider)
9f48053 [wallet] Allow descriptor imports with importmulti (MeshCollider)
d2b381c [wallet] Refactor ProcessImport() to call ProcessImportLegacy() (John Newbery)
4cac0dd [wallet] Add ProcessImportLegacy() (John Newbery)
a1b25e1 [wallet] Refactor ProcessImport() (John Newbery)

Pull request description:

  ~~Based on #14454 #14565, last two commits only are for review.~~

  Best reviewed with `?w=1`

  Allows a descriptor to be imported into the wallet using `importmulti` RPC. Start and end of range can be specified for ranged descriptors. The descriptor is implicitly converted to old structures on import.

  Also adds a simple test of a P2SH-P2WPKH address being imported as a descriptor. More tests to come, as well as release notes.

Tree-SHA512: 160eb6fd574c4ae5b70e0109f7e5ccc95d9309138603408a1114ceb3c558065409c0d7afb66926bc8e1743c365a3b300c5f944ff18b2451acc0514fbeca1f2b3
deadalnix pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request May 15, 2020
Summary:
Partial backport of Core [[bitcoin/bitcoin#14454 | PR14454]]
bitcoin/bitcoin@f6ed748
bitcoin/bitcoin@c11875c#diff-3dfbfa462305488434b8d8da81f99de7R99-R111

Depends on D6061

Test Plan:
    ninja
    ninja check
    ninja check-functional

Reviewers: O1 Bitcoin ABC, #bitcoin_abc, deadalnix

Reviewed By: O1 Bitcoin ABC, #bitcoin_abc, deadalnix

Subscribers: deadalnix

Differential Revision: https://reviews.bitcoinabc.org/D6051
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

importmulti P2WPKH issue SegWit support for importmulti
10 participants