Skip to content

Commit 13c842e

Browse files
committed
Merge #9332: Let wallet importmulti RPC accept labels for standard scriptPubKeys
98ea64c Let wallet importmulti RPC accept labels for standard scriptPubKeys (Russell Yanofsky) Pull request description: Allow importmulti RPC to apply address labels when importing standard scriptPubKeys. This makes the importmulti RPC less finnicky about import formats and also simpler internally. Tree-SHA512: 102426b21239f1fa5f38162dc3f4145572caef76e63906afd786b7aff1670d6cd93456f8d85f737588eedc49c11bef2e1e8019b8b2cbf6097c77b3501b0cab1f
2 parents e0a4f9d + 98ea64c commit 13c842e

File tree

3 files changed

+28
-51
lines changed

3 files changed

+28
-51
lines changed

src/wallet/rpcdump.cpp

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,9 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
849849

850850
std::vector<unsigned char> vData(ParseHex(output));
851851
script = CScript(vData.begin(), vData.end());
852+
if (!ExtractDestination(script, dest) && !internal) {
853+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
854+
}
852855
}
853856

854857
// Watchonly and private keys
@@ -861,11 +864,6 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
861864
throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
862865
}
863866

864-
// Not having Internal + Script
865-
if (!internal && isScript) {
866-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set for hex scriptPubKey");
867-
}
868-
869867
// Keys / PubKeys size check.
870868
if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey
871869
throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
@@ -969,21 +967,10 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
969967
CTxDestination pubkey_dest = pubKey.GetID();
970968

971969
// Consistency check.
972-
if (!isScript && !(pubkey_dest == dest)) {
970+
if (!(pubkey_dest == dest)) {
973971
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
974972
}
975973

976-
// Consistency check.
977-
if (isScript) {
978-
CTxDestination destination;
979-
980-
if (ExtractDestination(script, destination)) {
981-
if (!(destination == pubkey_dest)) {
982-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
983-
}
984-
}
985-
}
986-
987974
CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
988975

989976
if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
@@ -1034,21 +1021,10 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
10341021
CTxDestination pubkey_dest = pubKey.GetID();
10351022

10361023
// Consistency check.
1037-
if (!isScript && !(pubkey_dest == dest)) {
1024+
if (!(pubkey_dest == dest)) {
10381025
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
10391026
}
10401027

1041-
// Consistency check.
1042-
if (isScript) {
1043-
CTxDestination destination;
1044-
1045-
if (ExtractDestination(script, destination)) {
1046-
if (!(destination == pubkey_dest)) {
1047-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
1048-
}
1049-
}
1050-
}
1051-
10521028
CKeyID vchAddress = pubKey.GetID();
10531029
pwallet->MarkDirty();
10541030
pwallet->SetAddressBook(vchAddress, label, "receive");
@@ -1080,11 +1056,9 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
10801056
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
10811057
}
10821058

1083-
if (scriptPubKey.getType() == UniValue::VOBJ) {
1084-
// add to address book or update label
1085-
if (IsValidDestination(dest)) {
1086-
pwallet->SetAddressBook(dest, label, "receive");
1087-
}
1059+
// add to address book or update label
1060+
if (IsValidDestination(dest)) {
1061+
pwallet->SetAddressBook(dest, label, "receive");
10881062
}
10891063

10901064
success = true;

test/functional/wallet_import_rescan.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import enum
2727
import itertools
2828

29-
Call = enum.Enum("Call", "single multi")
29+
Call = enum.Enum("Call", "single multiaddress multiscript")
3030
Data = enum.Enum("Data", "address pub priv")
3131
Rescan = enum.Enum("Rescan", "no yes late_timestamp")
3232

@@ -53,11 +53,11 @@ def do_import(self, timestamp):
5353
response = self.try_rpc(self.node.importprivkey, privkey=self.key, rescan=rescan)
5454
assert_equal(response, None)
5555

56-
elif self.call == Call.multi:
56+
elif self.call in (Call.multiaddress, Call.multiscript):
5757
response = self.node.importmulti([{
5858
"scriptPubKey": {
5959
"address": self.address["address"]
60-
},
60+
} if self.call == Call.multiaddress else self.address["scriptPubKey"],
6161
"timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
6262
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
6363
"keys": [self.key] if self.data == Data.priv else [],
@@ -126,7 +126,7 @@ def run_test(self):
126126
for i, variant in enumerate(IMPORT_VARIANTS):
127127
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())
128128
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
129-
variant.initial_amount = 10 - (i + 1) / 4.0
129+
variant.initial_amount = 1 - (i + 1) / 64
130130
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
131131

132132
# Generate a block containing the initial transactions, then another
@@ -156,7 +156,7 @@ def run_test(self):
156156

157157
# Create new transactions sending to each address.
158158
for i, variant in enumerate(IMPORT_VARIANTS):
159-
variant.sent_amount = 10 - (2 * i + 1) / 8.0
159+
variant.sent_amount = 1 - (2 * i + 1) / 128
160160
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
161161

162162
# Generate a block containing the new transactions.

test/functional/wallet_importmulti.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test the importmulti RPC."""
6+
7+
from test_framework import script
68
from test_framework.test_framework import BitcoinTestFramework
79
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error
810

@@ -79,16 +81,17 @@ def run_test (self):
7981
assert_equal(address_assert['ismine'], False)
8082
assert_equal(address_assert['timestamp'], timestamp)
8183

82-
# ScriptPubKey + !internal
83-
self.log.info("Should not import a scriptPubKey without internal flag")
84+
# Nonstandard scriptPubKey + !internal
85+
self.log.info("Should not import a nonstandard scriptPubKey without internal flag")
86+
nonstandardScriptPubKey = address['scriptPubKey'] + bytes_to_hex_str(script.CScript([script.OP_NOP]))
8487
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
8588
result = self.nodes[1].importmulti([{
86-
"scriptPubKey": address['scriptPubKey'],
89+
"scriptPubKey": nonstandardScriptPubKey,
8790
"timestamp": "now",
8891
}])
8992
assert_equal(result[0]['success'], False)
9093
assert_equal(result[0]['error']['code'], -8)
91-
assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
94+
assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
9295
address_assert = self.nodes[1].getaddressinfo(address['address'])
9396
assert_equal(address_assert['iswatchonly'], False)
9497
assert_equal(address_assert['ismine'], False)
@@ -128,18 +131,18 @@ def run_test (self):
128131
assert_equal(address_assert['ismine'], False)
129132
assert_equal(address_assert['timestamp'], timestamp)
130133

131-
# ScriptPubKey + Public key + !internal
132-
self.log.info("Should not import a scriptPubKey without internal and with public key")
134+
# Nonstandard scriptPubKey + Public key + !internal
135+
self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key")
133136
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
134137
request = [{
135-
"scriptPubKey": address['scriptPubKey'],
138+
"scriptPubKey": nonstandardScriptPubKey,
136139
"timestamp": "now",
137140
"pubkeys": [ address['pubkey'] ]
138141
}]
139142
result = self.nodes[1].importmulti(request)
140143
assert_equal(result[0]['success'], False)
141144
assert_equal(result[0]['error']['code'], -8)
142-
assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
145+
assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
143146
address_assert = self.nodes[1].getaddressinfo(address['address'])
144147
assert_equal(address_assert['iswatchonly'], False)
145148
assert_equal(address_assert['ismine'], False)
@@ -207,17 +210,17 @@ def run_test (self):
207210
assert_equal(address_assert['ismine'], True)
208211
assert_equal(address_assert['timestamp'], timestamp)
209212

210-
# ScriptPubKey + Private key + !internal
211-
self.log.info("Should not import a scriptPubKey without internal and with private key")
213+
# Nonstandard scriptPubKey + Private key + !internal
214+
self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key")
212215
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
213216
result = self.nodes[1].importmulti([{
214-
"scriptPubKey": address['scriptPubKey'],
217+
"scriptPubKey": nonstandardScriptPubKey,
215218
"timestamp": "now",
216219
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
217220
}])
218221
assert_equal(result[0]['success'], False)
219222
assert_equal(result[0]['error']['code'], -8)
220-
assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
223+
assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
221224
address_assert = self.nodes[1].getaddressinfo(address['address'])
222225
assert_equal(address_assert['iswatchonly'], False)
223226
assert_equal(address_assert['ismine'], False)

0 commit comments

Comments
 (0)