aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Moore <dooglus@gmail.com>2017-09-12 14:01:12 -0700
committerAndrew Chow <achow101-github@achow101.com>2018-05-12 13:15:21 -0400
commitb5ba01a18707b1d50c4d073bd40e1e92d78d04c1 (patch)
treea5d778bd459b76b06aaf94532590878402ccd894
parentdd3c07acce7ab67f32a79393abf6227009bd440d (diff)
Add 'sethdseed' RPC to initialize or replace HD seed
-rw-r--r--src/qt/rpcconsole.cpp1
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/wallet/rpcwallet.cpp71
-rw-r--r--src/wallet/wallet.cpp4
-rw-r--r--src/wallet/wallet.h3
5 files changed, 80 insertions, 0 deletions
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 7924840d0b..4032729a84 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -70,6 +70,7 @@ namespace {
const QStringList historyFilter = QStringList()
<< "importprivkey"
<< "importmulti"
+ << "sethdseed"
<< "signmessagewithprivkey"
<< "signrawtransaction"
<< "signrawtransactionwithkey"
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 34c41b3b6b..475fe1e274 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -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" },
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 94e61aa20e..a7b2b05d9b 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -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"} },
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 9533e6ff56..3ca31ac9eb 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -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);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3208a20f0f..b6cdf041a8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -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