diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 34b8c1fb79..a88aa78d0b 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -639,3 +639,95 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) file.close(); return NullUniValue; } + +UniValue dumpblindingkey(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "dumpblindingkey \"address\"\n" + "\nDumps the private blinding key for a CT address in hex." + "\nArguments:\n" + "1. \"address\" (string, required) The CT address\n" + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); + } + if (!address.IsBlinded()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a CT address"); + } + + CTxDestination dest = address.Get(); + CScript script = GetScriptForDestination(dest); + CKey key; + key = pwalletMain->GetBlindingKey(&script); + if (key.IsValid()) { + CPubKey pubkey = key.GetPubKey(); + if (pubkey == address.GetBlindingKey()) { + return HexStr(key.begin(), key.end()); + } + } + // Just for backward compatibility + key = pwalletMain->GetBlindingKey(NULL); + if (key.IsValid()) { + CPubKey pubkey = key.GetPubKey(); + if (pubkey == address.GetBlindingKey()) { + return HexStr(key.begin(), key.end()); + } + } + throw JSONRPCError(RPC_WALLET_ERROR, "Blinding key for address is unknown"); +} + +UniValue importblindingkey(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() < 2 || params.size() > 2) + throw runtime_error( + "importblindingkey \"address\" \"blindinghex\"\n" + "\nImports a private blinding key in hex for a CT address." + "\nArguments:\n" + "1. \"address\" (string, required) The CT address\n" + "2. \"hexkey\" (string, required) The blinding key in hex\n" + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + CBitcoinAddress address(params[0].get_str()); + if (!address.IsValid()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); + } + if (!address.IsBlinded()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not a CT address"); + } + + if (!IsHex(params[1].get_str())) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal for key"); + } + std::vector keydata = ParseHex(params[1].get_str()); + if (keydata.size() != 32) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal key length"); + } + + CKey key; + key.Set(keydata.begin(), keydata.end(), true); + if (!key.IsValid() || key.GetPubKey() != address.GetBlindingKey()) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Address and key do not match"); + } + + uint256 keyval; + memcpy(keyval.begin(), &keydata[0], 32); + if (!pwalletMain->AddSpecificBlindingKey(CScriptID(GetScriptForDestination(address.Get())), keyval)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import blinding key"); + } + pwalletMain->MarkDirty(); + + return NullUniValue; +} diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0d7c1f3d9f..ae01a8e286 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2661,6 +2661,8 @@ extern UniValue dumpwallet(const UniValue& params, bool fHelp); extern UniValue importwallet(const UniValue& params, bool fHelp); extern UniValue importprunedfunds(const UniValue& params, bool fHelp); extern UniValue removeprunedfunds(const UniValue& params, bool fHelp); +extern UniValue dumpblindingkey(const UniValue& params, bool fHelp); +extern UniValue importblindingkey(const UniValue& params, bool fHelp); static const CRPCCommand commands[] = { // category name actor (function) okSafeMode @@ -2671,6 +2673,7 @@ static const CRPCCommand commands[] = { "wallet", "addmultisigaddress", &addmultisigaddress, true }, { "wallet", "addwitnessaddress", &addwitnessaddress, true }, { "wallet", "backupwallet", &backupwallet, true }, + { "wallet", "dumpblindingkey", &dumpblindingkey, true }, { "wallet", "dumpprivkey", &dumpprivkey, true }, { "wallet", "dumpwallet", &dumpwallet, true }, { "wallet", "encryptwallet", &encryptwallet, true }, @@ -2688,6 +2691,7 @@ static const CRPCCommand commands[] = { "wallet", "importprivkey", &importprivkey, true }, { "wallet", "importwallet", &importwallet, true }, { "wallet", "importaddress", &importaddress, true }, + { "wallet", "importblindingkey", &importblindingkey, true }, { "wallet", "importprunedfunds", &importprunedfunds, true }, { "wallet", "importpubkey", &importpubkey, true }, { "wallet", "keypoolrefill", &keypoolrefill, true },