mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 04:52:59 +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
|
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
|
||||||
|
|
||||||
CKey secret;
|
CKey secret;
|
||||||
|
|
||||||
|
// 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);
|
secret.MakeNewKey(fCompressed);
|
||||||
|
}
|
||||||
|
|
||||||
// Compressed public keys were introduced in version 0.6.0
|
// Compressed public keys were introduced in version 0.6.0
|
||||||
if (fCompressed)
|
if (fCompressed)
|
||||||
@ -100,9 +141,7 @@ CPubKey CWallet::GenerateNewKey()
|
|||||||
CPubKey pubkey = secret.GetPubKey();
|
CPubKey pubkey = secret.GetPubKey();
|
||||||
assert(secret.VerifyPubKey(pubkey));
|
assert(secret.VerifyPubKey(pubkey));
|
||||||
|
|
||||||
// Create new metadata
|
mapKeyMetadata[pubkey.GetID()] = metadata;
|
||||||
int64_t nCreationTime = GetTime();
|
|
||||||
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
|
|
||||||
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
|
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
|
||||||
nTimeFirstKey = nCreationTime;
|
nTimeFirstKey = nCreationTime;
|
||||||
|
|
||||||
@ -1049,6 +1088,37 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
|
|||||||
return nChange;
|
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 CWalletTx::GetTxTime() const
|
||||||
{
|
{
|
||||||
int64_t n = nTimeSmart;
|
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("-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("-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("-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("-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("-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));
|
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
|
||||||
@ -3145,6 +3216,13 @@ bool CWallet::InitLoadWallet()
|
|||||||
if (fFirstRun)
|
if (fFirstRun)
|
||||||
{
|
{
|
||||||
// Create new keyUser and set as default key
|
// 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;
|
CPubKey newDefaultKey;
|
||||||
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
|
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
|
||||||
walletInstance->SetDefaultKey(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 unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
|
||||||
static const bool DEFAULT_WALLETBROADCAST = true;
|
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;
|
extern const char * DEFAULT_WALLET_DAT;
|
||||||
|
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
@ -574,6 +577,9 @@ private:
|
|||||||
|
|
||||||
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
|
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
|
||||||
|
|
||||||
|
/* the hd chain data model (external chain counters) */
|
||||||
|
CHDChain hdChain;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
* Main wallet lock.
|
* Main wallet lock.
|
||||||
@ -887,6 +893,12 @@ public:
|
|||||||
static bool ParameterInteraction();
|
static bool ParameterInteraction();
|
||||||
|
|
||||||
bool BackupWallet(const std::string& strDest);
|
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. */
|
/** A key allocated from the key pool. */
|
||||||
|
@ -599,6 +599,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
return false;
|
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 (...)
|
} catch (...)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -1003,3 +1013,10 @@ bool CWalletDB::EraseDestData(const std::string &address, const std::string &key
|
|||||||
nWalletDBUpdated++;
|
nWalletDBUpdated++;
|
||||||
return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
|
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
|
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
|
class CKeyMetadata
|
||||||
{
|
{
|
||||||
public:
|
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, bool fOnlyKeys);
|
||||||
static bool Recover(CDBEnv& dbenv, const std::string& filename);
|
static bool Recover(CDBEnv& dbenv, const std::string& filename);
|
||||||
|
|
||||||
|
//! write the hdchain model (external chain child index counter)
|
||||||
|
bool WriteHDChain(const CHDChain& chain);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWalletDB(const CWalletDB&);
|
CWalletDB(const CWalletDB&);
|
||||||
void operator=(const CWalletDB&);
|
void operator=(const CWalletDB&);
|
||||||
|
Loading…
Reference in New Issue
Block a user