mirror of
https://github.com/jwinterm/myriadcoin.git
synced 2026-10-19 05:58:38 +02:00
Any problems seen during deserialization will throw an uncaught exception, crashing the entire bitcoin process. Properly return an error instead, so that we may at least log the error and gracefully shutdown other portions of the app.
491 lines
12 KiB
C++
491 lines
12 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2011 The Bitcoin developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
#ifndef BITCOIN_DB_H
|
|
#define BITCOIN_DB_H
|
|
|
|
#include "key.h"
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <db_cxx.h>
|
|
|
|
class CTxIndex;
|
|
class CDiskBlockIndex;
|
|
class CDiskTxPos;
|
|
class COutPoint;
|
|
class CAddress;
|
|
class CWalletTx;
|
|
class CWallet;
|
|
class CAccount;
|
|
class CAccountingEntry;
|
|
class CBlockLocator;
|
|
|
|
|
|
extern unsigned int nWalletDBUpdated;
|
|
extern DbEnv dbenv;
|
|
|
|
extern void DBFlush(bool fShutdown);
|
|
void ThreadFlushWalletDB(void* parg);
|
|
bool BackupWallet(const CWallet& wallet, const std::string& strDest);
|
|
|
|
|
|
|
|
class CDB
|
|
{
|
|
protected:
|
|
Db* pdb;
|
|
std::string strFile;
|
|
std::vector<DbTxn*> vTxn;
|
|
bool fReadOnly;
|
|
|
|
explicit CDB(const char* pszFile, const char* pszMode="r+");
|
|
~CDB() { Close(); }
|
|
public:
|
|
void Close();
|
|
private:
|
|
CDB(const CDB&);
|
|
void operator=(const CDB&);
|
|
|
|
protected:
|
|
template<typename K, typename T>
|
|
bool Read(const K& key, T& value)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Read
|
|
Dbt datValue;
|
|
datValue.set_flags(DB_DBT_MALLOC);
|
|
int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
if (datValue.get_data() == NULL)
|
|
return false;
|
|
|
|
// Unserialize value
|
|
try {
|
|
CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
|
|
ssValue >> value;
|
|
}
|
|
catch (std::exception &e) {
|
|
return false;
|
|
}
|
|
|
|
// Clear and free memory
|
|
memset(datValue.get_data(), 0, datValue.get_size());
|
|
free(datValue.get_data());
|
|
return (ret == 0);
|
|
}
|
|
|
|
template<typename K, typename T>
|
|
bool Write(const K& key, const T& value, bool fOverwrite=true)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
if (fReadOnly)
|
|
assert(!"Write called on database in read-only mode");
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Value
|
|
CDataStream ssValue(SER_DISK);
|
|
ssValue.reserve(10000);
|
|
ssValue << value;
|
|
Dbt datValue(&ssValue[0], ssValue.size());
|
|
|
|
// Write
|
|
int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
|
|
|
|
// Clear memory in case it was a private key
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
memset(datValue.get_data(), 0, datValue.get_size());
|
|
return (ret == 0);
|
|
}
|
|
|
|
template<typename K>
|
|
bool Erase(const K& key)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
if (fReadOnly)
|
|
assert(!"Erase called on database in read-only mode");
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Erase
|
|
int ret = pdb->del(GetTxn(), &datKey, 0);
|
|
|
|
// Clear memory
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
return (ret == 0 || ret == DB_NOTFOUND);
|
|
}
|
|
|
|
template<typename K>
|
|
bool Exists(const K& key)
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
|
|
// Key
|
|
CDataStream ssKey(SER_DISK);
|
|
ssKey.reserve(1000);
|
|
ssKey << key;
|
|
Dbt datKey(&ssKey[0], ssKey.size());
|
|
|
|
// Exists
|
|
int ret = pdb->exists(GetTxn(), &datKey, 0);
|
|
|
|
// Clear memory
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
return (ret == 0);
|
|
}
|
|
|
|
Dbc* GetCursor()
|
|
{
|
|
if (!pdb)
|
|
return NULL;
|
|
Dbc* pcursor = NULL;
|
|
int ret = pdb->cursor(NULL, &pcursor, 0);
|
|
if (ret != 0)
|
|
return NULL;
|
|
return pcursor;
|
|
}
|
|
|
|
int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
|
|
{
|
|
// Read at cursor
|
|
Dbt datKey;
|
|
if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
|
|
{
|
|
datKey.set_data(&ssKey[0]);
|
|
datKey.set_size(ssKey.size());
|
|
}
|
|
Dbt datValue;
|
|
if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
|
|
{
|
|
datValue.set_data(&ssValue[0]);
|
|
datValue.set_size(ssValue.size());
|
|
}
|
|
datKey.set_flags(DB_DBT_MALLOC);
|
|
datValue.set_flags(DB_DBT_MALLOC);
|
|
int ret = pcursor->get(&datKey, &datValue, fFlags);
|
|
if (ret != 0)
|
|
return ret;
|
|
else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
|
|
return 99999;
|
|
|
|
// Convert to streams
|
|
ssKey.SetType(SER_DISK);
|
|
ssKey.clear();
|
|
ssKey.write((char*)datKey.get_data(), datKey.get_size());
|
|
ssValue.SetType(SER_DISK);
|
|
ssValue.clear();
|
|
ssValue.write((char*)datValue.get_data(), datValue.get_size());
|
|
|
|
// Clear and free memory
|
|
memset(datKey.get_data(), 0, datKey.get_size());
|
|
memset(datValue.get_data(), 0, datValue.get_size());
|
|
free(datKey.get_data());
|
|
free(datValue.get_data());
|
|
return 0;
|
|
}
|
|
|
|
DbTxn* GetTxn()
|
|
{
|
|
if (!vTxn.empty())
|
|
return vTxn.back();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
public:
|
|
bool TxnBegin()
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
DbTxn* ptxn = NULL;
|
|
int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);
|
|
if (!ptxn || ret != 0)
|
|
return false;
|
|
vTxn.push_back(ptxn);
|
|
return true;
|
|
}
|
|
|
|
bool TxnCommit()
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
if (vTxn.empty())
|
|
return false;
|
|
int ret = vTxn.back()->commit(0);
|
|
vTxn.pop_back();
|
|
return (ret == 0);
|
|
}
|
|
|
|
bool TxnAbort()
|
|
{
|
|
if (!pdb)
|
|
return false;
|
|
if (vTxn.empty())
|
|
return false;
|
|
int ret = vTxn.back()->abort();
|
|
vTxn.pop_back();
|
|
return (ret == 0);
|
|
}
|
|
|
|
bool ReadVersion(int& nVersion)
|
|
{
|
|
nVersion = 0;
|
|
return Read(std::string("version"), nVersion);
|
|
}
|
|
|
|
bool WriteVersion(int nVersion)
|
|
{
|
|
return Write(std::string("version"), nVersion);
|
|
}
|
|
|
|
bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CTxDB : public CDB
|
|
{
|
|
public:
|
|
CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
|
|
private:
|
|
CTxDB(const CTxDB&);
|
|
void operator=(const CTxDB&);
|
|
public:
|
|
bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
|
|
bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
|
|
bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
|
|
bool EraseTxIndex(const CTransaction& tx);
|
|
bool ContainsTx(uint256 hash);
|
|
bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
|
|
bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
|
|
bool ReadDiskTx(uint256 hash, CTransaction& tx);
|
|
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
|
|
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
|
|
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
|
|
bool EraseBlockIndex(uint256 hash);
|
|
bool ReadHashBestChain(uint256& hashBestChain);
|
|
bool WriteHashBestChain(uint256 hashBestChain);
|
|
bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
|
|
bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
|
|
bool LoadBlockIndex();
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class CAddrDB : public CDB
|
|
{
|
|
public:
|
|
CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
|
|
private:
|
|
CAddrDB(const CAddrDB&);
|
|
void operator=(const CAddrDB&);
|
|
public:
|
|
bool WriteAddress(const CAddress& addr);
|
|
bool EraseAddress(const CAddress& addr);
|
|
bool LoadAddresses();
|
|
};
|
|
|
|
bool LoadAddresses();
|
|
|
|
|
|
|
|
class CKeyPool
|
|
{
|
|
public:
|
|
int64 nTime;
|
|
std::vector<unsigned char> vchPubKey;
|
|
|
|
CKeyPool()
|
|
{
|
|
nTime = GetTime();
|
|
}
|
|
|
|
CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
|
|
{
|
|
nTime = GetTime();
|
|
vchPubKey = vchPubKeyIn;
|
|
}
|
|
|
|
IMPLEMENT_SERIALIZE
|
|
(
|
|
if (!(nType & SER_GETHASH))
|
|
READWRITE(nVersion);
|
|
READWRITE(nTime);
|
|
READWRITE(vchPubKey);
|
|
)
|
|
};
|
|
|
|
|
|
|
|
|
|
enum DBErrors
|
|
{
|
|
DB_LOAD_OK,
|
|
DB_CORRUPT,
|
|
DB_TOO_NEW,
|
|
DB_LOAD_FAIL,
|
|
DB_NEED_REWRITE
|
|
};
|
|
|
|
class CWalletDB : public CDB
|
|
{
|
|
public:
|
|
CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
|
|
{
|
|
}
|
|
private:
|
|
CWalletDB(const CWalletDB&);
|
|
void operator=(const CWalletDB&);
|
|
public:
|
|
bool ReadName(const std::string& strAddress, std::string& strName)
|
|
{
|
|
strName = "";
|
|
return Read(std::make_pair(std::string("name"), strAddress), strName);
|
|
}
|
|
|
|
bool WriteName(const std::string& strAddress, const std::string& strName);
|
|
|
|
bool EraseName(const std::string& strAddress);
|
|
|
|
bool ReadTx(uint256 hash, CWalletTx& wtx)
|
|
{
|
|
return Read(std::make_pair(std::string("tx"), hash), wtx);
|
|
}
|
|
|
|
bool WriteTx(uint256 hash, const CWalletTx& wtx)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::make_pair(std::string("tx"), hash), wtx);
|
|
}
|
|
|
|
bool EraseTx(uint256 hash)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Erase(std::make_pair(std::string("tx"), hash));
|
|
}
|
|
|
|
bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
|
|
{
|
|
vchPrivKey.clear();
|
|
return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
|
|
}
|
|
|
|
bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
|
|
}
|
|
|
|
bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
|
|
{
|
|
nWalletDBUpdated++;
|
|
if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
|
|
return false;
|
|
if (fEraseUnencryptedKey)
|
|
{
|
|
Erase(std::make_pair(std::string("key"), vchPubKey));
|
|
Erase(std::make_pair(std::string("wkey"), vchPubKey));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
|
|
}
|
|
|
|
bool WriteBestBlock(const CBlockLocator& locator)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::string("bestblock"), locator);
|
|
}
|
|
|
|
bool ReadBestBlock(CBlockLocator& locator)
|
|
{
|
|
return Read(std::string("bestblock"), locator);
|
|
}
|
|
|
|
bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
|
|
{
|
|
vchPubKey.clear();
|
|
return Read(std::string("defaultkey"), vchPubKey);
|
|
}
|
|
|
|
bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::string("defaultkey"), vchPubKey);
|
|
}
|
|
|
|
bool ReadPool(int64 nPool, CKeyPool& keypool)
|
|
{
|
|
return Read(std::make_pair(std::string("pool"), nPool), keypool);
|
|
}
|
|
|
|
bool WritePool(int64 nPool, const CKeyPool& keypool)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::make_pair(std::string("pool"), nPool), keypool);
|
|
}
|
|
|
|
bool ErasePool(int64 nPool)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Erase(std::make_pair(std::string("pool"), nPool));
|
|
}
|
|
|
|
template<typename T>
|
|
bool ReadSetting(const std::string& strKey, T& value)
|
|
{
|
|
return Read(std::make_pair(std::string("setting"), strKey), value);
|
|
}
|
|
|
|
template<typename T>
|
|
bool WriteSetting(const std::string& strKey, const T& value)
|
|
{
|
|
nWalletDBUpdated++;
|
|
return Write(std::make_pair(std::string("setting"), strKey), value);
|
|
}
|
|
|
|
bool ReadAccount(const std::string& strAccount, CAccount& account);
|
|
bool WriteAccount(const std::string& strAccount, const CAccount& account);
|
|
bool WriteAccountingEntry(const CAccountingEntry& acentry);
|
|
int64 GetAccountCreditDebit(const std::string& strAccount);
|
|
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
|
|
|
|
int LoadWallet(CWallet* pwallet);
|
|
};
|
|
|
|
#endif
|