mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Make new actually working master blinding calls, test
This commit is contained in:
parent
09e20ab819
commit
9acbd24360
4 changed files with 136 additions and 18 deletions
|
|
@ -190,7 +190,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "sendmany", 8 , "output_assets" },
|
||||
{ "sendmany", 9 , "ignoreblindfail" },
|
||||
{ "sendtoaddress", 9 , "ignoreblindfail" },
|
||||
{ "importblindingkey", 2, "key_is_master"},
|
||||
{ "createrawtransaction", 4, "output_assets" },
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
|||
}
|
||||
// ELEMENTS: Dump the master blinding key in hex as well
|
||||
if (!pwallet->blinding_derivation_key.IsNull()) {
|
||||
file << ("# Master private blinding key: " + pwallet->blinding_derivation_key.GetHex() + "\n\n");
|
||||
file << ("# Master private blinding key: " + HexStr(pwallet->blinding_derivation_key) + "\n\n");
|
||||
}
|
||||
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
|
||||
const CKeyID &keyid = it->second;
|
||||
|
|
@ -1343,14 +1343,13 @@ UniValue importblindingkey(const JSONRPCRequest& request)
|
|||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
|
||||
if (request.fHelp || request.params.size() != 2)
|
||||
throw std::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"
|
||||
"3. \"key_is_master\" (bool, optional, default=false) If the `hexkey` is a master blinding key. Note: wallets can only have one master blinding key at a time. Funds could be permanently lost if user doesn't know what they are doing. Recommended use is only for wallet recovery using this in conjunction with `sethdseed`.\n"
|
||||
"\nExample:\n"
|
||||
+ HelpExampleCli("importblindingkey", "\"my blinded CT address\" <blindinghex>")
|
||||
);
|
||||
|
|
@ -1373,11 +1372,6 @@ UniValue importblindingkey(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal key length");
|
||||
}
|
||||
|
||||
bool key_is_master = false;
|
||||
if (!request.params[2].isNull()) {
|
||||
key_is_master = request.params[2].get_bool();
|
||||
}
|
||||
|
||||
CKey key;
|
||||
key.Set(keydata.begin(), keydata.end(), true);
|
||||
if (!key.IsValid() || key.GetPubKey() != GetDestinationBlindingKey(dest)) {
|
||||
|
|
@ -1386,20 +1380,56 @@ UniValue importblindingkey(const JSONRPCRequest& request)
|
|||
|
||||
uint256 keyval;
|
||||
memcpy(keyval.begin(), &keydata[0], 32);
|
||||
if (key_is_master) {
|
||||
if (pwallet->SetMasterBlindingKey(keyval)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import master blinding key");
|
||||
}
|
||||
} else {
|
||||
if (!pwallet->AddSpecificBlindingKey(CScriptID(GetScriptForDestination(dest)), keyval)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import blinding key");
|
||||
}
|
||||
if (!pwallet->AddSpecificBlindingKey(CScriptID(GetScriptForDestination(dest)), keyval)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import blinding key");
|
||||
}
|
||||
pwallet->MarkDirty();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
UniValue importmasterblindingkey(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
CWallet* const pwallet = wallet.get();
|
||||
|
||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() != 1)
|
||||
throw std::runtime_error(
|
||||
"importblindingkey \"address\" \"blindinghex\"\n"
|
||||
"\nImports a master private blinding key in hex for a CT address."
|
||||
"Note: wallets can only have one master blinding key at a time. Funds could be permanently lost if user doesn't know what they are doing. Recommended use is only for wallet recovery using this in conjunction with `sethdseed`.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"hexkey\" (string, required) The blinding key in hex\n"
|
||||
"\nExample:\n"
|
||||
+ HelpExampleCli("importmasterblindingkey", "<hexkey>")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwallet->cs_wallet);
|
||||
|
||||
if (!IsHex(request.params[0].get_str())) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal for key");
|
||||
}
|
||||
std::vector<unsigned char> keydata = ParseHex(request.params[0].get_str());
|
||||
if (keydata.size() != 32) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid hexadecimal key length");
|
||||
}
|
||||
|
||||
uint256 keyval;
|
||||
memcpy(keyval.begin(), &keydata[0], 32);
|
||||
|
||||
if (!pwallet->SetMasterBlindingKey(keyval)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to import master blinding key");
|
||||
}
|
||||
|
||||
pwallet->MarkDirty();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
UniValue importissuanceblindingkey(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
|
|
@ -1519,6 +1549,34 @@ UniValue dumpblindingkey(const JSONRPCRequest& request)
|
|||
throw JSONRPCError(RPC_WALLET_ERROR, "Blinding key for address is unknown");
|
||||
}
|
||||
|
||||
UniValue dumpmasterblindingkey(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
CWallet* const pwallet = wallet.get();
|
||||
|
||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() != 0)
|
||||
throw std::runtime_error(
|
||||
"dumpmasterblindingkey\n"
|
||||
"\nDumps the master private blinding key in hex."
|
||||
"\nResult:\n"
|
||||
"\"blindingkey\" (string) The master blinding key\n"
|
||||
"\nExample:\n"
|
||||
+ HelpExampleCli("dumpmasterblindingkey", "")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwallet->cs_wallet);
|
||||
|
||||
if (!pwallet->blinding_derivation_key.IsNull()) {
|
||||
return HexStr(pwallet->blinding_derivation_key);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Master blinding key is uninitialized.");
|
||||
}
|
||||
}
|
||||
|
||||
UniValue dumpissuanceblindingkey(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
|
|
|
|||
|
|
@ -6199,8 +6199,10 @@ UniValue getpegoutkeys(const JSONRPCRequest& request)
|
|||
UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue importblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue importmasterblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue importissuanceblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue dumpblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue dumpmasterblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue dumpissuanceblindingkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
UniValue importprivkey(const JSONRPCRequest& request);
|
||||
UniValue importaddress(const JSONRPCRequest& request);
|
||||
|
|
@ -6281,9 +6283,11 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "sendtomainchain", &sendtomainchain, {"address", "amount", "subtractfeefromamount"} },
|
||||
{ "wallet", "initpegoutwallet", &initpegoutwallet, {"bitcoin_descriptor", "bip32_counter", "liquid_pak"} },
|
||||
{ "wallet", "getwalletpakinfo", &getwalletpakinfo, {} },
|
||||
{ "wallet", "importblindingkey", &importblindingkey, {"address", "hexkey", "key_is_master"}},
|
||||
{ "wallet", "importblindingkey", &importblindingkey, {"address", "hexkey"}},
|
||||
{ "wallet", "importmasterblindingkey", &importmasterblindingkey, {"hexkey"}},
|
||||
{ "wallet", "importissuanceblindingkey", &importissuanceblindingkey, {"txid", "vin", "blindingkey"}},
|
||||
{ "wallet", "dumpblindingkey", &dumpblindingkey, {"address"}},
|
||||
{ "wallet", "dumpmasterblindingkey", &dumpmasterblindingkey, {}},
|
||||
{ "wallet", "dumpissuanceblindingkey", &dumpissuanceblindingkey, {"txid", "vin"}},
|
||||
{ "wallet", "signblock", &signblock, {"blockhex"}},
|
||||
{ "wallet", "listissuances", &listissuances, {"asset"}},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ from test_framework.test_framework import BitcoinTestFramework
|
|||
from test_framework.util import connect_nodes_bi, assert_equal
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from decimal import Decimal
|
||||
import os
|
||||
import re
|
||||
|
||||
class CTTest (BitcoinTestFramework):
|
||||
|
||||
|
|
@ -28,8 +30,63 @@ class CTTest (BitcoinTestFramework):
|
|||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def test_wallet_recovery(self):
|
||||
file_path = "/tmp/blind_details"
|
||||
try:
|
||||
os.remove(file_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Wallet recovery requires more than just seed, but also master blinding key
|
||||
# which currently is not derived from seed, see
|
||||
# https://github.com/ElementsProject/elements/pull/232
|
||||
blind_addr = self.nodes[0].getnewaddress()
|
||||
|
||||
self.nodes[0].dumpwallet(file_path)
|
||||
|
||||
found_seed = False
|
||||
found_blind = False
|
||||
with open(file_path, encoding="utf8") as f:
|
||||
for line in f:
|
||||
if "hdseed=1" in line:
|
||||
split = re.split(" ", line)
|
||||
found_seed = split[0]
|
||||
split = re.split("Master private blinding key: ", line)
|
||||
if len(split) == 2:
|
||||
assert_equal(len(split[1].rstrip()), 64)
|
||||
found_blind = split[1].rstrip()
|
||||
|
||||
assert_equal(found_blind, self.nodes[0].dumpmasterblindingkey())
|
||||
|
||||
# Create new wallet
|
||||
self.nodes[0].createwallet("recover")
|
||||
rec = self.nodes[0].get_wallet_rpc("recover")
|
||||
wrong_info = rec.getaddressinfo(blind_addr)
|
||||
assert("pubkey" not in wrong_info)
|
||||
assert_equal(wrong_info["ismine"], False)
|
||||
|
||||
# Setting seed should get us more info, still not "ours" until blinding key
|
||||
rec.generatetoaddress(1, rec.getnewaddress()) # get out of IBD
|
||||
rec.sethdseed(True, found_seed)
|
||||
|
||||
wrong_blind_info = rec.getaddressinfo(blind_addr)
|
||||
assert("pubkey" in wrong_blind_info)
|
||||
assert_equal(wrong_blind_info["ismine"], False)
|
||||
|
||||
# Now import master blinding key
|
||||
rec.importmasterblindingkey(found_blind)
|
||||
assert_equal(rec.dumpmasterblindingkey(), found_blind)
|
||||
blind_info = rec.getaddressinfo(blind_addr)
|
||||
assert("pubkey" in blind_info)
|
||||
assert_equal(blind_info["ismine"], True)
|
||||
assert_equal(rec.getaddressinfo(blind_info["unconfidential"])["confidential"], blind_addr)
|
||||
self.nodes[0].unloadwallet("recover")
|
||||
|
||||
def run_test(self):
|
||||
|
||||
print("Testing wallet secret recovery")
|
||||
self.test_wallet_recovery()
|
||||
|
||||
print("General Confidential tests")
|
||||
# Running balances
|
||||
node0 = self.nodes[0].getbalance()["bitcoin"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue