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()
|
const QStringList historyFilter = QStringList()
|
||||||
<< "importprivkey"
|
<< "importprivkey"
|
||||||
<< "importmulti"
|
<< "importmulti"
|
||||||
|
<< "sethdseed"
|
||||||
<< "signmessagewithprivkey"
|
<< "signmessagewithprivkey"
|
||||||
<< "signrawtransaction"
|
<< "signrawtransaction"
|
||||||
<< "signrawtransactionwithkey"
|
<< "signrawtransactionwithkey"
|
||||||
|
|
|
@ -38,6 +38,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||||
{ "sendtoaddress", 5 , "replaceable" },
|
{ "sendtoaddress", 5 , "replaceable" },
|
||||||
{ "sendtoaddress", 6 , "conf_target" },
|
{ "sendtoaddress", 6 , "conf_target" },
|
||||||
{ "settxfee", 0, "amount" },
|
{ "settxfee", 0, "amount" },
|
||||||
|
{ "sethdseed", 0, "newkeypool" },
|
||||||
{ "getreceivedbyaddress", 1, "minconf" },
|
{ "getreceivedbyaddress", 1, "minconf" },
|
||||||
{ "getreceivedbyaccount", 1, "minconf" },
|
{ "getreceivedbyaccount", 1, "minconf" },
|
||||||
{ "getreceivedbylabel", 1, "minconf" },
|
{ "getreceivedbylabel", 1, "minconf" },
|
||||||
|
|
|
@ -4079,6 +4079,76 @@ static UniValue listlabels(const JSONRPCRequest& request)
|
||||||
return ret;
|
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 abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||||
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
|
||||||
extern UniValue importprivkey(const JSONRPCRequest& request);
|
extern UniValue importprivkey(const JSONRPCRequest& request);
|
||||||
|
@ -4139,6 +4209,7 @@ static const CRPCCommand commands[] =
|
||||||
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
|
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
|
||||||
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
|
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
|
||||||
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
|
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
|
||||||
|
{ "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
|
||||||
|
|
||||||
/** Account functions (deprecated) */
|
/** Account functions (deprecated) */
|
||||||
{ "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
|
{ "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
|
||||||
|
|
|
@ -1452,7 +1452,11 @@ CPubKey CWallet::GenerateNewHDMasterKey()
|
||||||
{
|
{
|
||||||
CKey key;
|
CKey key;
|
||||||
key.MakeNewKey(true);
|
key.MakeNewKey(true);
|
||||||
|
return DeriveNewMasterHDKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPubKey CWallet::DeriveNewMasterHDKey(const CKey& key)
|
||||||
|
{
|
||||||
int64_t nCreationTime = GetTime();
|
int64_t nCreationTime = GetTime();
|
||||||
CKeyMetadata metadata(nCreationTime);
|
CKeyMetadata metadata(nCreationTime);
|
||||||
|
|
||||||
|
|
|
@ -1127,6 +1127,9 @@ public:
|
||||||
/* Generates a new HD master key (will not be activated) */
|
/* Generates a new HD master key (will not be activated) */
|
||||||
CPubKey GenerateNewHDMasterKey();
|
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)
|
/* 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
|
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
|
caller must ensure the current wallet version is correct before calling
|
||||||
|
|
Loading…
Reference in a new issue