Refactor keytime/metadata and wallet encryption bugfix

Refactor keytime:
* Key metadata is kept in a CWallet::mapKeyMetadata (std::map<CKeyId,CKeyMetadata>).
* When generating a new key, time is put in that map, and new key is written.
* AddKeyPubKey and AddCryptedKey do not take a creation time argument, but instead
  pull it from that map, if it exists there.

Bugfix:
* AddKeyPubKey and AddCryptedKey in CWallet didn't override the CKeyStore
  definition anymore. This is fixed, as they no longed need the nCreationTime
  argument now.

Also a few related other changes:
* Metadata can be overwritten.
* Only GenerateNewKey calls GetTime(), as it's the only place where we know for
  sure a key was not constructed earlier.
* When the nTimeFirstKey is known to be inaccurate, it is set to the value 1
  (instead of 0, which would mean unknown).
* Use CPubKey instead of std::vector<unsigned char> where possible.
This commit is contained in:
Pieter Wuille 2013-06-20 01:13:55 +02:00
parent 25dbb92860
commit 4addb2c066
4 changed files with 36 additions and 28 deletions

View file

@ -40,18 +40,20 @@ CPubKey CWallet::GenerateNewKey()
SetMinVersion(FEATURE_COMPRPUBKEY); SetMinVersion(FEATURE_COMPRPUBKEY);
CPubKey pubkey = secret.GetPubKey(); CPubKey pubkey = secret.GetPubKey();
// Create new metadata
int64 nCreationTime = GetTime();
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey)) if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
return pubkey; return pubkey;
} }
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey, bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
int64 nCreateTime)
{ {
if (!nCreateTime)
nCreateTime = GetTime();
if (!nTimeFirstKey || (nCreateTime < nTimeFirstKey))
nTimeFirstKey = nCreateTime;
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false; return false;
if (!fFileBacked) if (!fFileBacked)
@ -59,19 +61,14 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey,
if (!IsCrypted()) { if (!IsCrypted()) {
return CWalletDB(strWalletFile).WriteKey(pubkey, return CWalletDB(strWalletFile).WriteKey(pubkey,
secret.GetPrivKey(), secret.GetPrivKey(),
nCreateTime); mapKeyMetadata[pubkey.GetID()]);
} }
return true; return true;
} }
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const vector<unsigned char> &vchCryptedSecret, const vector<unsigned char> &vchCryptedSecret)
int64 nCreateTime)
{ {
if (!nCreateTime)
nCreateTime = GetTime();
if (!nTimeFirstKey || (nCreateTime < nTimeFirstKey))
nTimeFirstKey = nCreateTime;
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false; return false;
if (!fFileBacked) if (!fFileBacked)
@ -81,15 +78,24 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
if (pwalletdbEncryption) if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
vchCryptedSecret, vchCryptedSecret,
nCreateTime); mapKeyMetadata[vchPubKey.GetID()]);
else else
return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
vchCryptedSecret, vchCryptedSecret,
nCreateTime); mapKeyMetadata[vchPubKey.GetID()]);
} }
return false; return false;
} }
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
nTimeFirstKey = meta.nCreateTime;
mapKeyMetadata[pubkey.GetID()] = meta;
return true;
}
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{ {
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);

View file

@ -87,7 +87,7 @@ public:
std::string strWalletFile; std::string strWalletFile;
std::set<int64> setKeyPool; std::set<int64> setKeyPool;
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap; typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys; MasterKeyMap mapMasterKeys;
@ -140,14 +140,16 @@ public:
// Generate a new key // Generate a new key
CPubKey GenerateNewKey(); CPubKey GenerateNewKey();
// Adds a key to the store, and saves it to disk. // Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey, int64 nCreateTime = 0); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
// Adds a key to the store, without saving it to disk (used by LoadWallet) // Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
// Load metadata (used by LoadWallet)
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
// Adds an encrypted key to the store, and saves it to disk. // Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, int64 nCreateTime = 0); bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
// Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddCScript(const CScript& redeemScript); bool AddCScript(const CScript& redeemScript);

View file

@ -344,12 +344,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} }
else if (strType == "keymeta") else if (strType == "keymeta")
{ {
vector<unsigned char> vchPubKey; CPubKey vchPubKey;
ssKey >> vchPubKey; ssKey >> vchPubKey;
CKeyMetadata keyMeta; CKeyMetadata keyMeta;
ssValue >> keyMeta; ssValue >> keyMeta;
wss.nKeyMeta++; wss.nKeyMeta++;
pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
// find earliest key creation time, as wallet birthday // find earliest key creation time, as wallet birthday
if (!pwallet->nTimeFirstKey || if (!pwallet->nTimeFirstKey ||
(keyMeta.nCreateTime < pwallet->nTimeFirstKey)) (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
@ -483,7 +485,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
// nTimeFirstKey is only reliable if all keys have metadata // nTimeFirstKey is only reliable if all keys have metadata
if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
pwallet->nTimeFirstKey = 0; pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade) BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
WriteTx(hash, pwallet->mapWallet[hash]); WriteTx(hash, pwallet->mapWallet[hash]);

View file

@ -30,7 +30,7 @@ class CKeyMetadata
public: public:
static const int CURRENT_VERSION=1; static const int CURRENT_VERSION=1;
int nVersion; int nVersion;
int64 nCreateTime; int64 nCreateTime; // 0 means unknown
CKeyMetadata() CKeyMetadata()
{ {
@ -52,7 +52,7 @@ public:
void SetNull() void SetNull()
{ {
nVersion = CKeyMetadata::CURRENT_VERSION; nVersion = CKeyMetadata::CURRENT_VERSION;
nCreateTime = GetTime(); nCreateTime = 0;
} }
}; };
@ -84,13 +84,12 @@ public:
} }
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey,
int64 nCreateTime) const CKeyMetadata &keyMeta)
{ {
nWalletDBUpdated++; nWalletDBUpdated++;
CKeyMetadata keyMeta(nCreateTime);
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta, false)) keyMeta))
return false; return false;
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false); return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
@ -98,14 +97,13 @@ public:
bool WriteCryptedKey(const CPubKey& vchPubKey, bool WriteCryptedKey(const CPubKey& vchPubKey,
const std::vector<unsigned char>& vchCryptedSecret, const std::vector<unsigned char>& vchCryptedSecret,
int64 nCreateTime) const CKeyMetadata &keyMeta)
{ {
const bool fEraseUnencryptedKey = true; const bool fEraseUnencryptedKey = true;
nWalletDBUpdated++; nWalletDBUpdated++;
CKeyMetadata keyMeta(nCreateTime);
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey), if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta, false)) keyMeta))
return false; return false;
if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))