Add 'sethdseed' RPC to initialize or replace HD seed
This commit is contained in:
parent
dd3c07acce
commit
b5ba01a187
5 changed files with 80 additions and 0 deletions
|
@ -70,6 +70,7 @@ namespace {
|
|||
const QStringList historyFilter = QStringList()
|
||||
<< "importprivkey"
|
||||
<< "importmulti"
|
||||
<< "sethdseed"
|
||||
<< "signmessagewithprivkey"
|
||||
<< "signrawtransaction"
|
||||
<< "signrawtransactionwithkey"
|
||||
|
|
|
@ -38,6 +38,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "sendtoaddress", 5 , "replaceable" },
|
||||
{ "sendtoaddress", 6 , "conf_target" },
|
||||
{ "settxfee", 0, "amount" },
|
||||
{ "sethdseed", 0, "newkeypool" },
|
||||
{ "getreceivedbyaddress", 1, "minconf" },
|
||||
{ "getreceivedbyaccount", 1, "minconf" },
|
||||
{ "getreceivedbylabel", 1, "minconf" },
|
||||
|
|
|
@ -4079,6 +4079,76 @@ static UniValue listlabels(const JSONRPCRequest& request)
|
|||
return ret;
|
||||
}
|
||||
|
||||
UniValue sethdseed(const JSONRPCRequest& request)
|
||||
{
|
||||
CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
|
||||
|
||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() > 2) {
|
||||
throw std::runtime_error(
|
||||
"sethdseed ( \"newkeypool\" \"seed\" )\n"
|
||||
"\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
|
||||
"HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
|
||||
"\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed.\n"
|
||||
+ HelpRequiringPassphrase(pwallet) +
|
||||
"\nArguments:\n"
|
||||
"1. \"newkeypool\" (boolean, optional, default=true) Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
|
||||
" If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
|
||||
" If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
|
||||
" keypool will be used until it has been depleted.\n"
|
||||
"2. \"seed\" (string, optional) The WIF private key to use as the new HD seed; if not provided a random seed will be used.\n"
|
||||
" The seed value can be retrieved using the dumpwallet command. It is the private key marked hdmaster=1\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("sethdseed", "")
|
||||
+ HelpExampleCli("sethdseed", "false")
|
||||
+ HelpExampleCli("sethdseed", "true \"wifkey\"")
|
||||
+ HelpExampleRpc("sethdseed", "true, \"wifkey\"")
|
||||
);
|
||||
}
|
||||
|
||||
if (IsInitialBlockDownload()) {
|
||||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
|
||||
}
|
||||
|
||||
LOCK2(cs_main, pwallet->cs_wallet);
|
||||
|
||||
// Do not do anything to non-HD wallets
|
||||
if (!pwallet->IsHDEnabled()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD");
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
bool flush_key_pool = true;
|
||||
if (!request.params[0].isNull()) {
|
||||
flush_key_pool = request.params[0].get_bool();
|
||||
}
|
||||
|
||||
CPubKey master_pub_key;
|
||||
if (request.params[1].isNull()) {
|
||||
master_pub_key = pwallet->GenerateNewHDMasterKey();
|
||||
} else {
|
||||
CKey key = DecodeSecret(request.params[1].get_str());
|
||||
if (!key.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
|
||||
}
|
||||
|
||||
if (HaveKey(*pwallet, key)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
|
||||
}
|
||||
|
||||
master_pub_key = pwallet->DeriveNewMasterHDKey(key);
|
||||
}
|
||||
|
||||
pwallet->SetHDMasterKey(master_pub_key);
|
||||
if (flush_key_pool) pwallet->NewKeyPool();
|
||||
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||
extern UniValue importprivkey(const JSONRPCRequest& request);
|
||||
|
@ -4139,6 +4209,7 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
|
||||
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
|
||||
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
|
||||
{ "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
|
||||
|
||||
/** Account functions (deprecated) */
|
||||
{ "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
|
||||
|
|
|
@ -1452,7 +1452,11 @@ CPubKey CWallet::GenerateNewHDMasterKey()
|
|||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
return DeriveNewMasterHDKey(key);
|
||||
}
|
||||
|
||||
CPubKey CWallet::DeriveNewMasterHDKey(const CKey& key)
|
||||
{
|
||||
int64_t nCreationTime = GetTime();
|
||||
CKeyMetadata metadata(nCreationTime);
|
||||
|
||||
|
|
|
@ -1127,6 +1127,9 @@ public:
|
|||
/* Generates a new HD master key (will not be activated) */
|
||||
CPubKey GenerateNewHDMasterKey();
|
||||
|
||||
/* Derives a new HD master key (will not be activated) */
|
||||
CPubKey DeriveNewMasterHDKey(const CKey& key);
|
||||
|
||||
/* Set the current HD master key (will reset the chain child index counters)
|
||||
Sets the master key's version based on the current wallet version (so the
|
||||
caller must ensure the current wallet version is correct before calling
|
||||
|
|
Loading…
Reference in a new issue