Skip to content

Commit 98ea64c

Browse files
committed
Let wallet importmulti RPC accept labels for standard scriptPubKeys
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.
1 parent aae64a2 commit 98ea64c

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
@@ -838,6 +838,9 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
838838

839839
std::vector<unsigned char> vData(ParseHex(output));
840840
script = CScript(vData.begin(), vData.end());
841+
if (!ExtractDestination(script, dest) && !internal) {
842+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
843+
}
841844
}
842845

843846
// Watchonly and private keys
@@ -850,11 +853,6 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
850853
throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
851854
}
852855

853-
// Not having Internal + Script
854-
if (!internal && isScript) {
855-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set for hex scriptPubKey");
856-
}
857-
858856
// Keys / PubKeys size check.
859857
if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey
860858
throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
@@ -965,21 +963,10 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
965963
CTxDestination pubkey_dest = pubKey.GetID();
966964

967965
// Consistency check.
968-
if (!isScript && !(pubkey_dest == dest)) {
966+
if (!(pubkey_dest == dest)) {
969967
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
970968
}
971969

972-
// Consistency check.
973-
if (isScript) {
974-
CTxDestination destination;
975-
976-
if (ExtractDestination(script, destination)) {
977-
if (!(destination == pubkey_dest)) {
978-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
979-
}
980-
}
981-
}
982-
983970
CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
984971

985972
if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
@@ -1036,21 +1023,10 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
10361023
CTxDestination pubkey_dest = pubKey.GetID();
10371024

10381025
// Consistency check.
1039-
if (!isScript && !(pubkey_dest == dest)) {
1026+
if (!(pubkey_dest == dest)) {
10401027
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
10411028
}
10421029

1043-
// Consistency check.
1044-
if (isScript) {
1045-
CTxDestination destination;
1046-
1047-
if (ExtractDestination(script, destination)) {
1048-
if (!(destination == pubkey_dest)) {
1049-
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
1050-
}
1051-
}
1052-
}
1053-
10541030
CKeyID vchAddress = pubKey.GetID();
10551031
pwallet->MarkDirty();
10561032
pwallet->SetAddressBook(vchAddress, label, "receive");
@@ -1082,11 +1058,9 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
10821058
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
10831059
}
10841060

1085-
if (scriptPubKey.getType() == UniValue::VOBJ) {
1086-
// add to address book or update label
1087-
if (IsValidDestination(dest)) {
1088-
pwallet->SetAddressBook(dest, label, "receive");
1089-
}
1061+
// add to address book or update label
1062+
if (IsValidDestination(dest)) {
1063+
pwallet->SetAddressBook(dest, label, "receive");
10901064
}
10911065

10921066
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

@@ -54,11 +54,11 @@ def do_import(self, timestamp):
5454
response = self.try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes)
5555
assert_equal(response, None)
5656

57-
elif self.call == Call.multi:
57+
elif self.call in (Call.multiaddress, Call.multiscript):
5858
response = self.node.importmulti([{
5959
"scriptPubKey": {
6060
"address": self.address["address"]
61-
},
61+
} if self.call == Call.multiaddress else self.address["scriptPubKey"],
6262
"timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
6363
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
6464
"keys": [self.key] if self.data == Data.priv else [],
@@ -136,7 +136,7 @@ def run_test(self):
136136
variant.label = "label {} {}".format(i, variant)
137137
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))
138138
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
139-
variant.initial_amount = 10 - (i + 1) / 4.0
139+
variant.initial_amount = 1 - (i + 1) / 64
140140
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
141141

142142
# Generate a block containing the initial transactions, then another
@@ -166,7 +166,7 @@ def run_test(self):
166166

167167
# Create new transactions sending to each address.
168168
for i, variant in enumerate(IMPORT_VARIANTS):
169-
variant.sent_amount = 10 - (2 * i + 1) / 8.0
169+
variant.sent_amount = 1 - (2 * i + 1) / 128
170170
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
171171

172172
# 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 *
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)