mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
[Wallet] Add simplest BIP32/deterministic key generation implementation
This commit is contained in:
parent
950be19727
commit
f19025106d
@ -91,7 +91,48 @@ CPubKey CWallet::GenerateNewKey()
|
||||
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
|
||||
|
||||
CKey secret;
|
||||
secret.MakeNewKey(fCompressed);
|
||||
|
||||
// Create new metadata
|
||||
int64_t nCreationTime = GetTime();
|
||||
CKeyMetadata metadata(nCreationTime);
|
||||
|
||||
// use HD key derivation if HD was enabled during wallet creation
|
||||
if (!hdChain.masterKeyID.IsNull()) {
|
||||
// for now we use a fixed keypath scheme of m/0'/0'/k
|
||||
CKey key; //master key seed (256bit)
|
||||
CExtKey masterKey; //hd master key
|
||||
CExtKey accountKey; //key at m/0'
|
||||
CExtKey externalChainChildKey; //key at m/0'/0'
|
||||
CExtKey childKey; //key at m/0'/0'/<n>'
|
||||
|
||||
// try to get the master key
|
||||
if (!GetKey(hdChain.masterKeyID, key))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): Master key not found");
|
||||
|
||||
masterKey.SetMaster(key.begin(), key.size());
|
||||
|
||||
// derive m/0'
|
||||
// use hardened derivation (child keys > 0x80000000 are hardened after bip32)
|
||||
masterKey.Derive(accountKey, 0 | 0x80000000);
|
||||
|
||||
// derive m/0'/0'
|
||||
accountKey.Derive(externalChainChildKey, 0 | 0x80000000);
|
||||
|
||||
// derive child key at next index, skip keys already known to the wallet
|
||||
do
|
||||
{
|
||||
externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | 0x80000000);
|
||||
// increment childkey index
|
||||
hdChain.nExternalChainCounter++;
|
||||
} while(HaveKey(childKey.key.GetPubKey().GetID()));
|
||||
secret = childKey.key;
|
||||
|
||||
// update the chain model in the database
|
||||
if (!CWalletDB(strWalletFile).WriteHDChain(hdChain))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
|
||||
} else {
|
||||
secret.MakeNewKey(fCompressed);
|
||||
}
|
||||
|
||||
// Compressed public keys were introduced in version 0.6.0
|
||||
if (fCompressed)
|
||||
@ -100,9 +141,7 @@ CPubKey CWallet::GenerateNewKey()
|
||||
CPubKey pubkey = secret.GetPubKey();
|
||||
assert(secret.VerifyPubKey(pubkey));
|
||||
|
||||
// Create new metadata
|
||||
int64_t nCreationTime = GetTime();
|
||||
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
|
||||
mapKeyMetadata[pubkey.GetID()] = metadata;
|
||||
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
|
||||
nTimeFirstKey = nCreationTime;
|
||||
|
||||
@ -1049,6 +1088,37 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
|
||||
return nChange;
|
||||
}
|
||||
|
||||
bool CWallet::SetHDMasterKey(const CKey& key)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
// store the key as normal "key"/"ckey" object
|
||||
// in the database
|
||||
// key metadata is not required
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
if (!AddKeyPubKey(key, pubkey))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
|
||||
|
||||
// store the keyid (hash160) together with
|
||||
// the child index counter in the database
|
||||
// as a hdchain object
|
||||
CHDChain newHdChain;
|
||||
newHdChain.masterKeyID = pubkey.GetID();
|
||||
SetHDChain(newHdChain, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
|
||||
throw runtime_error("AddHDChain(): writing chain failed");
|
||||
|
||||
hdChain = chain;
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t CWalletTx::GetTxTime() const
|
||||
{
|
||||
int64_t n = nTimeSmart;
|
||||
@ -3058,6 +3128,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
|
||||
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
|
||||
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
|
||||
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
|
||||
strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after bip32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
|
||||
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
|
||||
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
|
||||
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
|
||||
@ -3145,6 +3216,13 @@ bool CWallet::InitLoadWallet()
|
||||
if (fFirstRun)
|
||||
{
|
||||
// Create new keyUser and set as default key
|
||||
if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET)) {
|
||||
// generate a new master key
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
if (!walletInstance->SetHDMasterKey(key))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed");
|
||||
}
|
||||
CPubKey newDefaultKey;
|
||||
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
|
||||
walletInstance->SetDefaultKey(newDefaultKey);
|
||||
|
@ -57,6 +57,9 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
|
||||
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
|
||||
static const bool DEFAULT_WALLETBROADCAST = true;
|
||||
|
||||
//! if set, all keys will be derived by using BIP32
|
||||
static const bool DEFAULT_USE_HD_WALLET = true;
|
||||
|
||||
extern const char * DEFAULT_WALLET_DAT;
|
||||
|
||||
class CBlockIndex;
|
||||
@ -574,6 +577,9 @@ private:
|
||||
|
||||
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
|
||||
|
||||
/* the hd chain data model (external chain counters) */
|
||||
CHDChain hdChain;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Main wallet lock.
|
||||
@ -887,6 +893,12 @@ public:
|
||||
static bool ParameterInteraction();
|
||||
|
||||
bool BackupWallet(const std::string& strDest);
|
||||
|
||||
/* Set the hd chain model (chain child index counters) */
|
||||
bool SetHDChain(const CHDChain& chain, bool memonly);
|
||||
|
||||
/* Set the current hd master key (will reset the chain child index counters) */
|
||||
bool SetHDMasterKey(const CKey& key);
|
||||
};
|
||||
|
||||
/** A key allocated from the key pool. */
|
||||
|
@ -599,6 +599,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (strType == "hdchain")
|
||||
{
|
||||
CHDChain chain;
|
||||
ssValue >> chain;
|
||||
if (!pwallet->SetHDChain(chain, true))
|
||||
{
|
||||
strErr = "Error reading wallet database: SetHDChain failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (...)
|
||||
{
|
||||
return false;
|
||||
@ -1003,3 +1013,10 @@ bool CWalletDB::EraseDestData(const std::string &address, const std::string &key
|
||||
nWalletDBUpdated++;
|
||||
return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
|
||||
}
|
||||
|
||||
|
||||
bool CWalletDB::WriteHDChain(const CHDChain& chain)
|
||||
{
|
||||
nWalletDBUpdated++;
|
||||
return Write(std::string("hdchain"), chain);
|
||||
}
|
||||
|
@ -40,6 +40,35 @@ enum DBErrors
|
||||
DB_NEED_REWRITE
|
||||
};
|
||||
|
||||
/* simple hd chain data model */
|
||||
class CHDChain
|
||||
{
|
||||
public:
|
||||
uint32_t nExternalChainCounter;
|
||||
CKeyID masterKeyID; //!< master key hash160
|
||||
|
||||
static const int CURRENT_VERSION = 1;
|
||||
int nVersion;
|
||||
|
||||
CHDChain() { SetNull(); }
|
||||
ADD_SERIALIZE_METHODS;
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||
{
|
||||
READWRITE(this->nVersion);
|
||||
nVersion = this->nVersion;
|
||||
READWRITE(nExternalChainCounter);
|
||||
READWRITE(masterKeyID);
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = CHDChain::CURRENT_VERSION;
|
||||
nExternalChainCounter = 0;
|
||||
masterKeyID.SetNull();
|
||||
}
|
||||
};
|
||||
|
||||
class CKeyMetadata
|
||||
{
|
||||
public:
|
||||
@ -134,6 +163,9 @@ public:
|
||||
static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
|
||||
static bool Recover(CDBEnv& dbenv, const std::string& filename);
|
||||
|
||||
//! write the hdchain model (external chain child index counter)
|
||||
bool WriteHDChain(const CHDChain& chain);
|
||||
|
||||
private:
|
||||
CWalletDB(const CWalletDB&);
|
||||
void operator=(const CWalletDB&);
|
||||
|
Loading…
Reference in New Issue
Block a user