shadowproject/shadow

View on GitHub
src/walletdb.h

Summary

Maintainability
Test Coverage
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 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_WALLETDB_H
#define BITCOIN_WALLETDB_H

#include "db.h"
#include "base58.h"
#include "stealth.h"
#include "ringsig.h"


/*
prefixes
    name
    acc
    acentry
    keymeta
    key
    ckey
    wkey
    mkey
    defaultkey
    sxAddr
    sxKeyMeta
    keymeta
    lastfilteredheight
    pool
    version
    cscript
    orderposnext
    minversion
    tx
    lao                 - locked anon output
    oao                 - owned anon output
    oal
    bestblock
    bestblockheader
    minversion
    ek32                - bip32 extended keypair
    eknm                - named extended key
    eacc                - extended account
    epak                - extended account key pack
    espk                - extended account stealth key pack
    ecpk                - extended account stealth child key pack
    flag                - named integer flag

    old:

*/

class CKeyPool;
class CAccount;
class CAccountingEntry;

/** Error statuses for the wallet database */
enum DBErrors
{
    DB_LOAD_OK,
    DB_CORRUPT,
    DB_NONCRITICAL_ERROR,
    DB_TOO_NEW,
    DB_LOAD_FAIL,
    DB_NEED_REWRITE
};

class CKeyMetadata
{
public:
    static const int CURRENT_VERSION=1;
    int nVersion;
    int64_t nCreateTime; // 0 means unknown

    CKeyMetadata()
    {
        SetNull();
    }
    CKeyMetadata(int64_t nCreateTime_)
    {
        nVersion = CKeyMetadata::CURRENT_VERSION;
        nCreateTime = nCreateTime_;
    }

    IMPLEMENT_SERIALIZE
    (
        READWRITE(this->nVersion);
        nVersion = this->nVersion;
        READWRITE(nCreateTime);
    )

    void SetNull()
    {
        nVersion = CKeyMetadata::CURRENT_VERSION;
        nCreateTime = 0;
    }
};

class CStealthKeyMetadata
{
// -- used to get secret for keys created by stealth transaction with wallet locked
public:
    CStealthKeyMetadata() {}

    CStealthKeyMetadata(CPubKey pkEphem_, CPubKey pkScan_)
    {
        pkEphem = pkEphem_;
        pkScan = pkScan_;
    }

    CPubKey pkEphem;
    CPubKey pkScan;

    IMPLEMENT_SERIALIZE
    (
        READWRITE(pkEphem);
        READWRITE(pkScan);
    )

};

class CLockedAnonOutput
{
// expand key for anon output received with wallet locked
// stored in walletdb, key is pubkey hash160
public:
    CLockedAnonOutput() {}

    CLockedAnonOutput(CPubKey pkEphem_, CPubKey pkScan_, COutPoint outpoint_)
    {
        pkEphem = pkEphem_;
        pkScan = pkScan_;
        outpoint = outpoint_;
    }

    CPubKey   pkEphem;
    CPubKey   pkScan;
    COutPoint outpoint;

    IMPLEMENT_SERIALIZE
    (
        READWRITE(pkEphem);
        READWRITE(pkScan);
        READWRITE(outpoint);
    )

};

class COwnedAnonOutput
{
// stored in walletdb, key is keyimage
// TODO: store nValue?
public:
    COwnedAnonOutput() {}

    COwnedAnonOutput(COutPoint outpoint_, bool fSpent_)
    {
        outpoint = outpoint_;
        fSpent   = fSpent_;
    }

    ec_point vchImage;
    int64_t nValue;

    COutPoint outpoint;
    bool fSpent;

    IMPLEMENT_SERIALIZE
    (
        READWRITE(outpoint);
        READWRITE(fSpent);
    )

};


/** Access to the wallet database (wallet.dat) */
class CWalletDB : public CDB
{
public:
    CWalletDB(const std::string& strFilename, const char* pszMode = "r+") : CDB(strFilename, pszMode)
    {
    }
private:
    CWalletDB(const CWalletDB&);
    void operator=(const CWalletDB&);
public:
    Dbc* GetAtCursor()
    {
        return GetCursor();
    }

    Dbc* GetTxnCursor()
    {
        if (!pdb)
            return NULL;

        DbTxn* ptxnid = activeTxn; // call TxnBegin first

        Dbc* pcursor = NULL;
        int ret = pdb->cursor(ptxnid, &pcursor, 0);
        if (ret != 0)
            return NULL;
        return pcursor;
    }

    DbTxn* GetAtActiveTxn()
    {
        return activeTxn;
    }

    template< typename T>
    bool Replace(Dbc *pcursor, const T& value)
    {
        if (!pcursor)
            return false;

        if (fReadOnly)
            assert(!"Replace called on database in read-only mode");

        // Value
        CDataStream ssValue(SER_DISK, CLIENT_VERSION);
        ssValue.reserve(10000);
        ssValue << value;
        Dbt datValue(&ssValue[0], ssValue.size());

        // Write
        int ret = pcursor->put(NULL, &datValue, DB_CURRENT);

        if (ret != 0)
        {
            LogPrintf("CursorPut ret %d - %s\n", ret, DbEnv::strerror(ret));
        }
        // Clear memory in case it was a private key
        memset(datValue.get_data(), 0, datValue.get_size());

        return (ret == 0);
    }


    bool WriteName(const std::string& strAddress, const std::string& strName);

    bool EraseName(const std::string& strAddress);

    bool EraseRange(const std::string& sPrefix, uint32_t &nAffected);

    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 ReadLockedAnonOutput(const CKeyID& keyId, CLockedAnonOutput& lockedAo)
    {
        return Read(std::make_pair(std::string("lao"), keyId), lockedAo);
    }

    bool WriteLockedAnonOutput(const CKeyID& keyId, const CLockedAnonOutput& lockedAo)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("lao"), keyId), lockedAo, true);
    }

    bool EraseLockedAnonOutput(const CKeyID& keyId)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("lao"), keyId));
    }

    bool ReadOwnedAnonOutput(const ec_point& vchImage, COwnedAnonOutput& ownAo)
    {
        return Read(std::make_pair(std::string("oao"), vchImage), ownAo);
    }

    bool WriteOwnedAnonOutput(const ec_point& vchImage, const COwnedAnonOutput& ownAo)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("oao"), vchImage), ownAo, true);
    }

    bool EraseOwnedAnonOutput(const ec_point& vchImage)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("oao"), vchImage));
    }

    bool ReadOwnedAnonOutputLink(const CPubKey& pkCoin, ec_point& vchImage)
    {
        return Read(std::make_pair(std::string("oal"), pkCoin), vchImage);
    }

    bool WriteOwnedAnonOutputLink(const CPubKey& pkCoin, const ec_point& vchImage)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("oal"), pkCoin), vchImage, true);
    }

    bool EraseOwnedAnonOutputLink(const CPubKey& pkCoin)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("oal"), pkCoin));
    }

    bool ReadOldOutputLink(const ec_point& pkImage, ec_point& vchImage)
    {
        return Read(std::make_pair(std::string("ool"), pkImage), vchImage);
    }

    bool WriteOldOutputLink(const ec_point& pkImage, const ec_point& vchImage)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("ool"), pkImage), vchImage, true);
    }

    bool EraseOldOutputLink(const ec_point& pkImage)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("ool"), pkImage));
    }


    bool WriteStealthKeyMeta(const CKeyID& keyId, const CStealthKeyMetadata& sxKeyMeta)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("sxKeyMeta"), keyId), sxKeyMeta, true);
    }

    bool EraseStealthKeyMeta(const CKeyID& keyId)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("sxKeyMeta"), keyId));
    }

    bool WriteStealthAddress(const CStealthAddress& sxAddr)
    {
        nWalletDBUpdated++;

        return Write(std::make_pair(std::string("sxAddr"), sxAddr.scan_pubkey), sxAddr, true);
    }

    bool ReadStealthAddress(CStealthAddress& sxAddr)
    {
        // -- set scan_pubkey before reading
        return Read(std::make_pair(std::string("sxAddr"), sxAddr.scan_pubkey), sxAddr);
    }

    bool EraseStealthAddress(const CStealthAddress& sxAddr)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("sxAddr"), sxAddr.scan_pubkey));
    }

    bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta);

    bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, const CKeyMetadata &keyMeta);

    bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
    }

    bool WriteCScript(const uint160& hash, const CScript& redeemScript)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
    }

    bool WriteBestBlock(const CBlockLocator& locator)
    {
        nWalletDBUpdated++;
        return Write(std::string("bestblock"), locator);
    }

    bool ReadBestBlock(CBlockLocator& locator)
    {
        return Read(std::string("bestblock"), locator);
    }

    bool WriteBestBlockThin(const CBlockThinLocator& locator)
    {
        nWalletDBUpdated++;
        return Write(std::string("bestblockheader"), locator);
    }

    bool ReadBestBlockThin(CBlockThinLocator& locator)
    {
        return Read(std::string("bestblockheader"), locator);
    }

    bool WriteLastFilteredHeight(const int64_t& height)
    {
        nWalletDBUpdated++;
        return Write(std::string("lastfilteredheight"), height);
    }

    bool ReadLastFilteredHeight(int64_t& height)
    {
        return Read(std::string("lastfilteredheight"), height);
    }

    bool WriteOrderPosNext(int64_t nOrderPosNext)
    {
        nWalletDBUpdated++;
        return Write(std::string("orderposnext"), nOrderPosNext);
    }

    bool WriteDefaultKey(const CPubKey& vchPubKey);

    bool ReadPool(int64_t nPool, CKeyPool& keypool)
    {
        return Read(std::make_pair(std::string("pool"), nPool), keypool);
    }

    bool WritePool(int64_t nPool, const CKeyPool& keypool)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("pool"), nPool), keypool);
    }

    bool ErasePool(int64_t nPool)
    {
        nWalletDBUpdated++;
        return Erase(std::make_pair(std::string("pool"), nPool));
    }

    bool WriteMinVersion(int nVersion)
    {
        return Write(std::string("minversion"), nVersion);
    }

    bool ReadNamedExtKeyId(const std::string &name, CKeyID &identifier, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(std::make_pair(std::string("eknm"), name), identifier, nFlags);
    }

    bool WriteNamedExtKeyId(const std::string &name, const CKeyID &identifier)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("eknm"), name), identifier, true);
    }

    bool ReadExtKey(const CKeyID &identifier, CStoredExtKey &ek32, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(std::make_pair(std::string("ek32"), identifier), ek32, nFlags);
    }

    bool WriteExtKey(const CKeyID &identifier, const CStoredExtKey &ek32)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("ek32"), identifier), ek32, true);
    }

    bool ReadExtAccount(const CKeyID &identifier, CExtKeyAccount &ekAcc, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(std::make_pair(std::string("eacc"), identifier), ekAcc, nFlags);
    }

    bool WriteExtAccount(const CKeyID &identifier, const CExtKeyAccount &ekAcc)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("eacc"), identifier), ekAcc, true);
    }

    bool ReadExtKeyPack(const CKeyID &identifier, const uint32_t nPack, std::vector<CEKAKeyPack> &ekPak, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(boost::make_tuple(std::string("epak"), identifier, nPack), ekPak, nFlags);
    }

    bool WriteExtKeyPack(const CKeyID &identifier, const uint32_t nPack, const std::vector<CEKAKeyPack> &ekPak)
    {
        nWalletDBUpdated++;
        return Write(boost::make_tuple(std::string("epak"), identifier, nPack), ekPak, true);
    }

    bool ReadExtStealthKeyPack(const CKeyID &identifier, const uint32_t nPack, std::vector<CEKAStealthKeyPack> &aksPak, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(boost::make_tuple(std::string("espk"), identifier, nPack), aksPak, nFlags);
    }

    bool WriteExtStealthKeyPack(const CKeyID &identifier, const uint32_t nPack, const std::vector<CEKAStealthKeyPack> &aksPak)
    {
        nWalletDBUpdated++;
        return Write(boost::make_tuple(std::string("espk"), identifier, nPack), aksPak, true);
    }

    bool ReadExtStealthKeyChildPack(const CKeyID &identifier, const uint32_t nPack, std::vector<CEKASCKeyPack> &asckPak, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(boost::make_tuple(std::string("ecpk"), identifier, nPack), asckPak, nFlags);
    }

    bool WriteExtStealthKeyChildPack(const CKeyID &identifier, const uint32_t nPack, const std::vector<CEKASCKeyPack> &asckPak)
    {
        nWalletDBUpdated++;
        return Write(boost::make_tuple(std::string("ecpk"), identifier, nPack), asckPak, true);
    }

    bool ReadFlag(const std::string &name, int32_t &nValue, uint32_t nFlags=DB_READ_UNCOMMITTED)
    {
        return Read(std::make_pair(std::string("flag"), name), nValue, nFlags);
    }

    bool WriteFlag(const std::string &name, int32_t nValue)
    {
        nWalletDBUpdated++;
        return Write(std::make_pair(std::string("flag"), name), nValue, true);
    }


    bool ReadAccount(const std::string& strAccount, CAccount& account);
    bool WriteAccount(const std::string& strAccount, const CAccount& account);
private:
    bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
public:
    bool WriteAccountingEntry(const CAccountingEntry& acentry);
    int64_t GetAccountCreditDebit(const std::string& strAccount);
    void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);

    DBErrors ReorderTransactions(CWallet*);
    DBErrors LoadWallet(CWallet* pwallet);
    static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
    static bool Recover(CDBEnv& dbenv, std::string filename);
};

#endif // BITCOIN_WALLETDB_H