@@ -808,29 +808,24 @@ UniValue dumpwallet(const JSONRPCRequest& request)
808
808
static UniValue ProcessImport (CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
809
809
{
810
810
try {
811
- bool success = false ;
812
-
813
- // Required fields.
811
+ // First ensure scriptPubKey has either a script or JSON with "address" string
814
812
const UniValue& scriptPubKey = data[" scriptPubKey" ];
815
-
816
- // Should have script or JSON with "address".
817
- if (!(scriptPubKey.getType () == UniValue::VOBJ && scriptPubKey.exists (" address" )) && !(scriptPubKey.getType () == UniValue::VSTR)) {
818
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid scriptPubKey" );
813
+ bool isScript = scriptPubKey.getType () == UniValue::VSTR;
814
+ if (!isScript && !(scriptPubKey.getType () == UniValue::VOBJ && scriptPubKey.exists (" address" ))) {
815
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " scriptPubKey must be string with script or JSON with address string" );
819
816
}
817
+ const std::string& output = isScript ? scriptPubKey.get_str () : scriptPubKey[" address" ].get_str ();
820
818
821
819
// Optional fields.
822
820
const std::string& strRedeemScript = data.exists (" redeemscript" ) ? data[" redeemscript" ].get_str () : " " ;
821
+ const std::string& witness_script_hex = data.exists (" witnessscript" ) ? data[" witnessscript" ].get_str () : " " ;
823
822
const UniValue& pubKeys = data.exists (" pubkeys" ) ? data[" pubkeys" ].get_array () : UniValue ();
824
823
const UniValue& keys = data.exists (" keys" ) ? data[" keys" ].get_array () : UniValue ();
825
824
const bool internal = data.exists (" internal" ) ? data[" internal" ].get_bool () : false ;
826
825
const bool watchOnly = data.exists (" watchonly" ) ? data[" watchonly" ].get_bool () : false ;
827
- const std::string& label = data.exists (" label" ) && !internal ? data[" label" ].get_str () : " " ;
828
-
829
- bool isScript = scriptPubKey.getType () == UniValue::VSTR;
830
- bool isP2SH = strRedeemScript.length () > 0 ;
831
- const std::string& output = isScript ? scriptPubKey.get_str () : scriptPubKey[" address" ].get_str ();
826
+ const std::string& label = data.exists (" label" ) ? data[" label" ].get_str () : " " ;
832
827
833
- // Parse the output.
828
+ // Generate the script and destination for the scriptPubKey provided
834
829
CScript script;
835
830
CTxDestination dest;
836
831
@@ -854,35 +849,38 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
854
849
855
850
// Watchonly and private keys
856
851
if (watchOnly && keys.size ()) {
857
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Incompatibility found between watchonly and keys" );
852
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Watch-only addresses should not include private keys" );
858
853
}
859
854
860
- // Internal + Label
855
+ // Internal addresses should not have a label
861
856
if (internal && data.exists (" label" )) {
862
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Incompatibility found between internal and label" );
857
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Internal addresses should not have a label" );
863
858
}
864
859
865
- // Keys / PubKeys size check.
866
- if (!isP2SH && (keys. size () > 1 || pubKeys. size () > 1 )) { // Address / scriptPubKey
867
- throw JSONRPCError (RPC_INVALID_PARAMETER, " More than private key given for one address " );
860
+ // Force users to provide the witness script in its field rather than redeemscript
861
+ if (!strRedeemScript. empty () && script. IsPayToWitnessScriptHash ()) {
862
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " P2WSH addresses have an empty redeemscript. Please provide the witnessscript instead. " );
868
863
}
869
864
870
- // Invalid P2SH redeemScript
871
- if (isP2SH && !IsHex (strRedeemScript)) {
872
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid redeem script" );
873
- }
874
-
875
- // Process. //
865
+ CScript scriptpubkey_script = script;
866
+ CTxDestination scriptpubkey_dest = dest;
867
+ bool allow_p2wpkh = true ;
876
868
877
869
// P2SH
878
- if (isP2SH) {
870
+ if (!strRedeemScript.empty () && script.IsPayToScriptHash ()) {
871
+ // Check the redeemScript is valid
872
+ if (!IsHex (strRedeemScript)) {
873
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid redeem script: must be hex string" );
874
+ }
875
+
879
876
// Import redeem script.
880
877
std::vector<unsigned char > vData (ParseHex (strRedeemScript));
881
878
CScript redeemScript = CScript (vData.begin (), vData.end ());
879
+ CScriptID redeem_id (redeemScript);
882
880
883
- // Invalid P2SH address
884
- if (!script. IsPayToScriptHash () ) {
885
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid P2SH address / script " );
881
+ // Check that the redeemScript and scriptPubKey match
882
+ if (GetScriptForDestination (redeem_id) != script ) {
883
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " The redeemScript does not match the scriptPubKey " );
886
884
}
887
885
888
886
pwallet->MarkDirty ();
@@ -891,103 +889,83 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
891
889
throw JSONRPCError (RPC_WALLET_ERROR, " Error adding address to wallet" );
892
890
}
893
891
894
- CScriptID redeem_id (redeemScript);
895
892
if (!pwallet->HaveCScript (redeem_id) && !pwallet->AddCScript (redeemScript)) {
896
893
throw JSONRPCError (RPC_WALLET_ERROR, " Error adding p2sh redeemScript to wallet" );
897
894
}
898
895
899
- CScript redeemDestination = GetScriptForDestination (redeem_id);
896
+ // Now set script to the redeemScript so we parse the inner script as P2WSH or P2WPKH below
897
+ script = redeemScript;
898
+ ExtractDestination (script, dest);
899
+ }
900
900
901
- if (::IsMine (*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
902
- throw JSONRPCError (RPC_WALLET_ERROR, " The wallet already contains the private key for this address or script" );
901
+ // (P2SH-)P2WSH
902
+ if (!witness_script_hex.empty () && script.IsPayToWitnessScriptHash ()) {
903
+ if (!IsHex (witness_script_hex)) {
904
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid witness script: must be hex string" );
903
905
}
904
906
905
- pwallet->MarkDirty ();
907
+ // Generate the scripts
908
+ std::vector<unsigned char > witness_script_parsed (ParseHex (witness_script_hex));
909
+ CScript witness_script = CScript (witness_script_parsed.begin (), witness_script_parsed.end ());
910
+ CScriptID witness_id (witness_script);
906
911
907
- if (!pwallet->AddWatchOnly (redeemDestination, timestamp)) {
908
- throw JSONRPCError (RPC_WALLET_ERROR, " Error adding address to wallet" );
912
+ // Check that the witnessScript and scriptPubKey match
913
+ if (GetScriptForDestination (WitnessV0ScriptHash (witness_script)) != script) {
914
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " The witnessScript does not match the scriptPubKey or redeemScript" );
909
915
}
910
916
911
- // add to address book or update label
912
- if (IsValidDestination (dest )) {
913
- pwallet-> SetAddressBook (dest, label, " receive " );
917
+ // Add the witness script as watch only only if it is not for P2SH-P2WSH
918
+ if (!scriptpubkey_script. IsPayToScriptHash () && !pwallet-> AddWatchOnly (witness_script, timestamp )) {
919
+ throw JSONRPCError (RPC_WALLET_ERROR, " Error adding address to wallet " );
914
920
}
915
921
916
- // Import private keys.
917
- if (keys.size ()) {
918
- for (size_t i = 0 ; i < keys.size (); i++) {
919
- const std::string& privkey = keys[i].get_str ();
920
-
921
- CKey key = DecodeSecret (privkey);
922
-
923
- if (!key.IsValid ()) {
924
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid private key encoding" );
925
- }
926
-
927
- CPubKey pubkey = key.GetPubKey ();
928
- assert (key.VerifyPubKey (pubkey));
929
-
930
- CKeyID vchAddress = pubkey.GetID ();
931
- pwallet->MarkDirty ();
932
- pwallet->SetAddressBook (vchAddress, label, " receive" );
933
-
934
- if (pwallet->HaveKey (vchAddress)) {
935
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Already have this key" );
936
- }
937
-
938
- pwallet->mapKeyMetadata [vchAddress].nCreateTime = timestamp;
922
+ if (!pwallet->HaveCScript (witness_id) && !pwallet->AddCScript (witness_script)) {
923
+ throw JSONRPCError (RPC_WALLET_ERROR, " Error adding p2wsh witnessScript to wallet" );
924
+ }
939
925
940
- if (!pwallet->AddKeyPubKey (key, pubkey)) {
941
- throw JSONRPCError (RPC_WALLET_ERROR, " Error adding key to wallet" );
942
- }
926
+ // Now set script to the witnessScript so we parse the inner script as P2PK or P2PKH below
927
+ script = witness_script;
928
+ ExtractDestination (script, dest);
929
+ allow_p2wpkh = false ; // P2WPKH cannot be embedded in P2WSH
930
+ }
943
931
944
- pwallet->UpdateTimeFirstKey (timestamp);
945
- }
932
+ // (P2SH-)P2PK/P2PKH/P2WPKH
933
+ if (dest.type () == typeid (CKeyID) || dest.type () == typeid (WitnessV0KeyHash)) {
934
+ if (!allow_p2wpkh && dest.type () == typeid (WitnessV0KeyHash)) {
935
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " P2WPKH cannot be embedded in P2WSH" );
946
936
}
947
-
948
- success = true ;
949
- } else {
950
- // Import public keys.
951
- if (pubKeys.size () && keys.size () == 0 ) {
937
+ if (keys.size () > 1 || pubKeys.size () > 1 ) {
938
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " More than one key given for one single-key address" );
939
+ }
940
+ CPubKey pubkey;
941
+ if (keys.size ()) {
942
+ pubkey = DecodeSecret (keys[0 ].get_str ()).GetPubKey ();
943
+ }
944
+ if (pubKeys.size ()) {
952
945
const std::string& strPubKey = pubKeys[0 ].get_str ();
953
-
954
946
if (!IsHex (strPubKey)) {
955
947
throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Pubkey must be a hex string" );
956
948
}
957
-
958
- std::vector<unsigned char > vData (ParseHex (strPubKey));
959
- CPubKey pubKey (vData.begin (), vData.end ());
960
-
961
- if (!pubKey.IsFullyValid ()) {
962
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Pubkey is not a valid public key" );
963
- }
964
-
965
- CTxDestination pubkey_dest = pubKey.GetID ();
966
-
967
- // Consistency check.
968
- if (!(pubkey_dest == dest)) {
969
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Consistency check failed" );
970
- }
971
-
972
- CScript pubKeyScript = GetScriptForDestination (pubkey_dest);
973
-
974
- if (::IsMine (*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
975
- throw JSONRPCError (RPC_WALLET_ERROR, " The wallet already contains the private key for this address or script" );
949
+ std::vector<unsigned char > vData (ParseHex (pubKeys[0 ].get_str ()));
950
+ CPubKey pubkey_temp (vData.begin (), vData.end ());
951
+ if (pubkey.size () && pubkey_temp != pubkey) {
952
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Private key does not match public key for address" );
976
953
}
977
-
978
- pwallet-> MarkDirty ();
979
-
980
- if (!pwallet-> AddWatchOnly (pubKeyScript, timestamp )) {
981
- throw JSONRPCError (RPC_WALLET_ERROR , " Error adding address to wallet " );
954
+ pubkey = pubkey_temp;
955
+ }
956
+ if (pubkey. size () > 0 ) {
957
+ if (!pubkey. IsFullyValid ( )) {
958
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY , " Pubkey is not a valid public key " );
982
959
}
983
960
984
- // add to address book or update label
985
- if (IsValidDestination (pubkey_dest)) {
986
- pwallet->SetAddressBook (pubkey_dest, label, " receive" );
961
+ // Check the key corresponds to the destination given
962
+ std::vector<CTxDestination> destinations = GetAllDestinationsForKey (pubkey);
963
+ if (std::find (destinations.begin (), destinations.end (), dest) == destinations.end ()) {
964
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Key does not match address destination" );
987
965
}
988
966
989
- // TODO Is this necessary?
990
- CScript scriptRawPubKey = GetScriptForRawPubKey (pubKey );
967
+ // This is necessary to force the wallet to import the pubKey
968
+ CScript scriptRawPubKey = GetScriptForRawPubKey (pubkey );
991
969
992
970
if (::IsMine (*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) {
993
971
throw JSONRPCError (RPC_WALLET_ERROR, " The wallet already contains the private key for this address or script" );
@@ -998,73 +976,61 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
998
976
if (!pwallet->AddWatchOnly (scriptRawPubKey, timestamp)) {
999
977
throw JSONRPCError (RPC_WALLET_ERROR, " Error adding address to wallet" );
1000
978
}
1001
-
1002
- success = true ;
1003
979
}
980
+ }
1004
981
1005
- // Import private keys.
1006
- if (keys.size ()) {
1007
- const std::string& strPrivkey = keys[0 ].get_str ();
1008
-
1009
- // Checks.
1010
- CKey key = DecodeSecret (strPrivkey);
1011
-
1012
- if (!key.IsValid ()) {
1013
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid private key encoding" );
1014
- }
1015
-
1016
- CPubKey pubKey = key.GetPubKey ();
1017
- assert (key.VerifyPubKey (pubKey));
1018
-
1019
- CTxDestination pubkey_dest = pubKey.GetID ();
982
+ // Import the address
983
+ if (::IsMine (*pwallet, scriptpubkey_script) == ISMINE_SPENDABLE) {
984
+ throw JSONRPCError (RPC_WALLET_ERROR, " The wallet already contains the private key for this address or script" );
985
+ }
1020
986
1021
- // Consistency check.
1022
- if (!(pubkey_dest == dest)) {
1023
- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Consistency check failed" );
1024
- }
987
+ pwallet->MarkDirty ();
1025
988
1026
- CKeyID vchAddress = pubKey. GetID ();
1027
- pwallet-> MarkDirty ( );
1028
- pwallet-> SetAddressBook (vchAddress, label, " receive " );
989
+ if (!pwallet-> AddWatchOnly (scriptpubkey_script, timestamp)) {
990
+ throw JSONRPCError (RPC_WALLET_ERROR, " Error adding address to wallet " );
991
+ }
1029
992
1030
- if ( pwallet->HaveKey (vchAddress )) {
1031
- throw JSONRPCError (RPC_WALLET_ERROR, " The wallet already contains the private key for this address or script " );
1032
- }
993
+ if (!watchOnly && !pwallet-> HaveCScript ( CScriptID (scriptpubkey_script)) && ! pwallet->AddCScript (scriptpubkey_script )) {
994
+ throw JSONRPCError (RPC_WALLET_ERROR, " Error adding scriptPubKey script to wallet " );
995
+ }
1033
996
1034
- pwallet->mapKeyMetadata [vchAddress].nCreateTime = timestamp;
997
+ // add to address book or update label
998
+ if (IsValidDestination (scriptpubkey_dest)) {
999
+ pwallet->SetAddressBook (scriptpubkey_dest, label, " receive" );
1000
+ }
1035
1001
1036
- if (!pwallet-> AddKeyPubKey (key, pubKey)) {
1037
- throw JSONRPCError (RPC_WALLET_ERROR, " Error adding key to wallet " );
1038
- }
1002
+ // Import private keys.
1003
+ for ( size_t i = 0 ; i < keys. size (); i++) {
1004
+ const std::string& strPrivkey = keys[i]. get_str ();
1039
1005
1040
- pwallet->UpdateTimeFirstKey (timestamp);
1006
+ // Checks.
1007
+ CKey key = DecodeSecret (strPrivkey);
1041
1008
1042
- success = true ;
1009
+ if (!key.IsValid ()) {
1010
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid private key encoding" );
1043
1011
}
1044
1012
1045
- // Import scriptPubKey only.
1046
- if (pubKeys.size () == 0 && keys.size () == 0 ) {
1047
- if (::IsMine (*pwallet, script) == ISMINE_SPENDABLE) {
1048
- throw JSONRPCError (RPC_WALLET_ERROR, " The wallet already contains the private key for this address or script" );
1049
- }
1013
+ CPubKey pubKey = key.GetPubKey ();
1014
+ assert (key.VerifyPubKey (pubKey));
1050
1015
1051
- pwallet->MarkDirty ();
1016
+ CKeyID vchAddress = pubKey.GetID ();
1017
+ pwallet->MarkDirty ();
1052
1018
1053
- if (! pwallet->AddWatchOnly (script, timestamp )) {
1054
- throw JSONRPCError (RPC_WALLET_ERROR , " Error adding address to wallet " );
1055
- }
1019
+ if (pwallet->HaveKey (vchAddress )) {
1020
+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY , " Already have this key " );
1021
+ }
1056
1022
1057
- // add to address book or update label
1058
- if (IsValidDestination (dest)) {
1059
- pwallet->SetAddressBook (dest, label, " receive" );
1060
- }
1023
+ pwallet->mapKeyMetadata [vchAddress].nCreateTime = timestamp;
1061
1024
1062
- success = true ;
1025
+ if (!pwallet->AddKeyPubKey (key, pubKey)) {
1026
+ throw JSONRPCError (RPC_WALLET_ERROR, " Error adding key to wallet" );
1063
1027
}
1028
+
1029
+ pwallet->UpdateTimeFirstKey (timestamp);
1064
1030
}
1065
1031
1066
1032
UniValue result = UniValue (UniValue::VOBJ);
1067
- result.pushKV (" success" , UniValue (success ));
1033
+ result.pushKV (" success" , UniValue (true ));
1068
1034
return result;
1069
1035
} catch (const UniValue& e) {
1070
1036
UniValue result = UniValue (UniValue::VOBJ);
@@ -1117,7 +1083,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
1117
1083
" \" now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n "
1118
1084
" 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n "
1119
1085
" creation time of all keys being imported by the importmulti call will be scanned.\n "
1120
- " \" redeemscript\" : \" <script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n "
1086
+ " \" redeemscript\" : \" <script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey\n "
1087
+ " \" witnessscript\" : \" <script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey\n "
1121
1088
" \" pubkeys\" : [\" <pubKey>\" , ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n "
1122
1089
" \" keys\" : [\" <key>\" , ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n "
1123
1090
" \" internal\" : <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n "
0 commit comments