// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "db.h"
-#include "kernel.h"
-#include "checkpoints.h"
#include "util.h"
#include "main.h"
+#include "kernel.h"
+#include "checkpoints.h"
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
dbenv.set_lg_bsize(1048576);
dbenv.set_lg_max(10485760);
- dbenv.set_lk_max_locks(10000);
- dbenv.set_lk_max_objects(10000);
+ dbenv.set_lk_max_locks(40000);
+ dbenv.set_lk_max_objects(40000);
dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
dbenv.set_flags(DB_AUTO_COMMIT, 1);
dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
return false;
}
-void CDB::Close()
+void CDB::Flush()
{
- if (!pdb)
- return;
if (activeTxn)
- activeTxn->abort();
- activeTxn = NULL;
- pdb = NULL;
+ return;
// Flush database activity from memory pool to disk log
unsigned int nMinutes = 0;
nMinutes = 5;
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
+}
+
+void CDB::Close()
+{
+ if (!pdb)
+ return;
+ if (activeTxn)
+ activeTxn->abort();
+ activeTxn = NULL;
+ pdb = NULL;
+
+ Flush();
{
LOCK(bitdb.cs_db);
return Write(make_pair('f', nFile), info);
}
-bool CChainDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
- return Read(make_pair('f', nFile), info);
-}
-
-bool CChainDB::WriteLastBlockFile(int nFile) {
- return Write('l', nFile);
-}
-
-bool CChainDB::ReadLastBlockFile(int &nFile) {
- return Read('l', nFile);
-}
-
bool CChainDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
{
return Read('H', hashCheckpoint);
return Write('K', strPubKey);
}
+
+bool CChainDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
+ return Read(make_pair('f', nFile), info);
+}
+
+bool CChainDB::WriteLastBlockFile(int nFile) {
+ return Write('l', nFile);
+}
+
+bool CChainDB::ReadLastBlockFile(int &nFile) {
+ return Read('l', nFile);
+}
+
+CCoinsViewDB::CCoinsViewDB() : db("cr+") {}
+bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { return db.ReadCoins(txid, coins); }
+bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) { return db.WriteCoins(txid, coins); }
+bool CCoinsViewDB::HaveCoins(uint256 txid) { return db.HaveCoins(txid); }
+CBlockIndex *CCoinsViewDB::GetBestBlock() {
+ uint256 hashBestChain;
+ if (!db.ReadHashBestChain(hashBestChain))
+ return NULL;
+ std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
+ if (it == mapBlockIndex.end())
+ return NULL;
+ return it->second;
+}
+bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) { return db.WriteHashBestChain(pindex->GetBlockHash()); }
+bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
+ printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
+
+ if (!db.TxnBegin())
+ return false;
+ bool fOk = true;
+ for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) {
+ fOk = db.WriteCoins(it->first, it->second);
+ if (!fOk)
+ break;
+ }
+ if (fOk)
+ fOk = db.WriteHashBestChain(pindex->GetBlockHash());
+
+ if (!fOk)
+ db.TxnAbort();
+ else
+ fOk = db.TxnCommit();
+
+ return fOk;
+}
+
CBlockIndex static * InsertBlockIndex(uint256 hash)
{
if (hash == 0)
return pindexNew;
}
-bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
+bool LoadBlockIndex(CChainDB &chaindb)
{
if (!chaindb.LoadBlockIndexGuts())
return false;
{
CBlockIndex* pindex = item.second;
pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
- // NovaCoin: calculate stake modifier checksum
+
+ // Calculate stake modifier checksum
pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier);
printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
// Load hashBestChain pointer to end of best chain
- if (!coindb.ReadHashBestChain(hashBestChain))
+ pindexBest = pcoinsTip->GetBestBlock();
+ if (pindexBest == NULL)
{
if (pindexGenesisBlock == NULL)
return true;
return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
}
- std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
- if (it == mapBlockIndex.end()) {
- return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
- } else {
- // set 'next' pointers in best chain
- CBlockIndex *pindex = it->second;
- while(pindex != NULL && pindex->pprev != NULL) {
- CBlockIndex *pindexPrev = pindex->pprev;
- pindexPrev->pnext = pindex;
- pindex = pindexPrev;
- }
- pindexBest = it->second;
- nBestHeight = pindexBest->nHeight;
- nBestChainTrust = pindexBest->nChainTrust;
+ hashBestChain = pindexBest->GetBlockHash();
+ nBestHeight = pindexBest->nHeight;
+ nBestChainTrust = pindexBest->nChainTrust;
+
+ // set 'next' pointers in best chain
+ CBlockIndex *pindex = pindexBest;
+ while(pindex != NULL && pindex->pprev != NULL) {
+ CBlockIndex *pindexPrev = pindex->pprev;
+ pindexPrev->pnext = pindex;
+ pindex = pindexPrev;
}
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
// use file size to size memory buffer
int fileSize = GetFilesize(filein);
int dataSize = fileSize - sizeof(uint256);
- //Don't try to resize to a negative number if file is small
- if ( dataSize < 0 ) dataSize = 0;
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
explicit CDB(const char* pszFile, const char* pszMode="r+");
~CDB() { Close(); }
public:
+ void Flush();
void Close();
private:
CDB(const CDB&);
bool WriteHashBestChain(uint256 hashBestChain);
};
+
+/** CCoinsView backed by a CCoinsDB */
+class CCoinsViewDB : public CCoinsView
+{
+protected:
+ CCoinsDB db;
+public:
+ CCoinsViewDB();
+ bool GetCoins(uint256 txid, CCoins &coins);
+ bool SetCoins(uint256 txid, const CCoins &coins);
+ bool HaveCoins(uint256 txid);
+ CBlockIndex *GetBestBlock();
+ bool SetBestBlock(CBlockIndex *pindex);
+ bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+};
+
+
/** Access to the block database (chain.dat) */
class CChainDB : public CDB
{
};
-bool LoadBlockIndex(CCoinsDB &coinsdb, CChainDB &chaindb);
+bool LoadBlockIndex(CChainDB &chaindb);
/** Access to the (IP) address database (peers.dat) */
#endif
}
+static CCoinsViewDB *pcoinsdbview;
+
void Shutdown(void* parg)
{
static CCriticalSection cs_Shutdown;
nTransactionsUpdated++;
bitdb.Flush(false);
StopNode();
+ {
+ LOCK(cs_main);
+ pcoinsTip->Flush();
+ delete pcoinsTip;
+ delete pcoinsdbview;
+ }
bitdb.Flush(true);
boost::filesystem::remove(GetPidFile());
UnregisterWallet(pwalletMain);
uiInterface.InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
+ pcoinsdbview = new CCoinsViewDB();
+ pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+
if (!LoadBlockIndex())
return InitError(_("Error loading blkindex.dat"));
-
// as LoadBlockIndex can take several minutes, it's possible the user
// requested to kill bitcoin-qt during the last operation. If so, exit.
// As the program has not fully started yet, Shutdown() is possibly overkill.
CTransaction txPrev;
CCoins coins;
- CCoinsDB coindb("r");
- CCoinsViewDB view(coindb);
+ CCoinsViewCache &view = *pcoinsTip;
if (!view.GetCoins(txin.prevout.hash, coins))
return tx.DoS(1, error("CheckProofOfStake() : INFO: read coins for txPrev failed")); // previous transaction not in main chain, may occur during initial download
bool CCoinsView::HaveCoins(uint256 txid) { return false; }
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
+bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
-CCoinsViewDB::CCoinsViewDB(CCoinsDB &dbIn) : db(dbIn) {}
-bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { return db.ReadCoins(txid, coins); }
-bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) { return db.WriteCoins(txid, coins); }
-bool CCoinsViewDB::HaveCoins(uint256 txid) { return db.HaveCoins(txid); }
-CBlockIndex *CCoinsViewDB::GetBestBlock() { return pindexBest; }
-bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) { return db.WriteHashBestChain(pindex->GetBlockHash()); }
+bool CCoinsViewBacked::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); }
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
return true;
}
-bool CCoinsViewCache::Flush() {
- for (std::map<uint256,CCoins>::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
- if (!base->SetCoins(it->first, it->second))
- return false;
- }
- if (!base->SetBestBlock(pindexTip))
- return false;
- cacheCoins.clear();
- pindexTip = NULL;
+bool CCoinsViewCache::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
+ for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
+ cacheCoins[it->first] = it->second;
+ pindexTip = pindex;
return true;
}
+bool CCoinsViewCache::Flush() {
+ bool fOk = base->BatchWrite(cacheCoins, pindexTip);
+ if (fOk)
+ cacheCoins.clear();
+ return fOk;
+}
+
+unsigned int CCoinsViewCache::GetCacheSize() {
+ return cacheCoins.size();
+}
+
/** CCoinsView that brings transactions from a memorypool into view.
It does not check for spendings by memory pool transactions. */
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
return mempool.exists(txid) || base->HaveCoins(txid);
}
+CCoinsViewCache *pcoinsTip = NULL;
//////////////////////////////////////////////////////////////////////////////
//
else
{
CBlock blockTmp;
-
if (pblock == NULL) {
- CCoinsDB coinsdb("r");
CCoins coins;
- if (coinsdb.ReadCoins(GetHash(), coins)) {
+ if (pcoinsTip->GetCoins(GetHash(), coins)) {
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
if (pindex) {
if (!blockTmp.ReadFromDisk(pindex))
if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake())
return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
- // NovaCoin: enforce minimum output amount for user transactions until 1 May 2014 04:00:00 GMT
+ // Enforce minimum output amount for user transactions until 1 May 2014 04:00:00 GMT
if (!fTestNet && !IsCoinBase() && !txout.IsEmpty() && nTime < OUTPUT_SWITCH_TIME && txout.nValue < MIN_TXOUT_AMOUNT)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum"));
}
}
-bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs)
+bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs)
{
if (pfMissingInputs)
*pfMissingInputs = false;
if (fCheckInputs)
{
- CCoinsViewDB viewDB(coinsdb);
- CCoinsViewMemPool viewMemPool(viewDB, mempool);
- CCoinsViewCache view(viewMemPool);
+ CCoinsViewCache &view = *pcoinsTip;
// do we already have it?
if (view.HaveCoins(hash))
return true;
}
-bool CTransaction::AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs, bool* pfMissingInputs)
+bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
{
- return mempool.accept(coinsdb, *this, fCheckInputs, pfMissingInputs);
+ return mempool.accept(*this, fCheckInputs, pfMissingInputs);
}
bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
}
-bool CMerkleTx::AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs)
+bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs)
{
if (fClient)
{
if (!IsInMainChain() && !ClientCheckInputs())
return false;
- return CTransaction::AcceptToMemoryPool(coinsdb, false);
+ return CTransaction::AcceptToMemoryPool(false);
}
else
{
- return CTransaction::AcceptToMemoryPool(coinsdb, fCheckInputs);
+ return CTransaction::AcceptToMemoryPool(fCheckInputs);
}
}
-bool CMerkleTx::AcceptToMemoryPool()
-{
- CCoinsDB coinsdb("r");
- return AcceptToMemoryPool(coinsdb);
-}
-
-bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
+bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
{
{
if (!(tx.IsCoinBase() || tx.IsCoinStake()))
{
uint256 hash = tx.GetHash();
- if (!mempool.exists(hash) && !coinsdb.HaveCoins(hash))
- tx.AcceptToMemoryPool(coinsdb, fCheckInputs);
+ if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash))
+ tx.AcceptToMemoryPool(fCheckInputs);
}
}
- return AcceptToMemoryPool(coinsdb, fCheckInputs);
+ return AcceptToMemoryPool(fCheckInputs);
}
return false;
}
-bool CWalletTx::AcceptWalletTransaction()
-{
- CCoinsDB coinsdb("r");
- return AcceptWalletTransaction(coinsdb);
-}
-
// Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
{
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
int nHeight = -1;
{
- CCoinsDB coindb("r");
- CCoinsViewDB view(coindb);
+ CCoinsViewCache &view = *pcoinsTip;
CCoins coins;
if (view.GetCoins(hash, coins))
nHeight = coins.nHeight;
// Coin stake tx earns reward instead of paying fee
uint64 nCoinAge;
- if (!GetCoinAge(inputs, nCoinAge))
+ if (!GetCoinAge(nCoinAge))
return error("CheckInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
int64 nStakeReward = GetValueOut() - nValueIn;
bool CBlock::SetBestChain(CBlockIndex* pindexNew)
{
- // if this functions exits prematurely, the transaction is aborted
- CCoinsDB coinsdb;
- if (!coinsdb.TxnBegin())
- return error("SetBestChain() : TxnBegin failed");
+ CCoinsViewCache &view = *pcoinsTip;
// special case for attaching the genesis block
// note that no ConnectBlock is called, so its coinbase output is non-spendable
if (pindexGenesisBlock == NULL && pindexNew->GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
{
- coinsdb.WriteHashBestChain(pindexNew->GetBlockHash());
- if (!coinsdb.TxnCommit())
- return error("SetBestChain() : TxnCommit failed");
+ view.SetBestBlock(pindexNew);
+ if (!view.Flush())
+ return false;
pindexGenesisBlock = pindexNew;
pindexBest = pindexNew;
hashBestChain = pindexNew->GetBlockHash();
return true;
}
- // create cached view to the coins database
- CCoinsViewDB viewDB(coinsdb);
- CCoinsViewCache view(viewDB);
-
// Find the fork (typically, there is none)
CBlockIndex* pfork = view.GetBestBlock();
CBlockIndex* plonger = pindexNew;
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("SetBestBlock() : ReadFromDisk for disconnect failed");
- if (!block.DisconnectBlock(pindex, view))
+ CCoinsViewCache viewTemp(view, true);
+ if (!block.DisconnectBlock(pindex, viewTemp))
return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ if (!viewTemp.Flush())
+ return error("SetBestBlock() : Cache flush failed after disconnect");
// Queue memory transactions to resurrect
BOOST_FOREACH(const CTransaction& tx, block.vtx)
return error("SetBestBlock() : ReadFromDisk for connect failed");
pblock = █
}
- if (!pblock->ConnectBlock(pindex, view)) {
+ CCoinsViewCache viewTemp(view, true);
+ if (!pblock->ConnectBlock(pindex, viewTemp)) {
InvalidChainFound(pindexNew);
return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
}
+ if (!viewTemp.Flush())
+ return error("SetBestBlock() : Cache flush failed after connect");
// Queue memory transactions to delete
BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
}
// Make sure it's successfully written to disk before changing memory structure
- if (!view.Flush())
- return error("SetBestBlock() : failed to write coin changes");
- if (!coinsdb.TxnCommit())
- return error("SetBestBlock() : TxnCommit failed");
- coinsdb.Close();
+ bool fIsInitialDownload = IsInitialBlockDownload();
+ if (!fIsInitialDownload || view.GetCacheSize()>5000)
+ if (!view.Flush())
+ return false;
// At this point, all changes have been done to the database.
// Proceed by updating the memory structures.
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect)
- tx.AcceptToMemoryPool(coinsdb, false);
+ tx.AcceptToMemoryPool(false);
// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH(CTransaction& tx, vDelete)
mempool.remove(tx);
// Update best block in wallet (so we can detect restored wallets)
- bool fIsInitialDownload = IsInitialBlockDownload();
if (!fIsInitialDownload)
{
const CBlockLocator locator(pindexNew);
// guaranteed to be in main chain by sync-checkpoint. This rule is
// introduced to help nodes establish a consistent view of the coin
// age (trust score) of competing branches.
-bool CTransaction::GetCoinAge(CCoinsView& inputs, uint64& nCoinAge) const
+bool CTransaction::GetCoinAge(uint64& nCoinAge) const
{
+ CCoinsViewCache &inputs = *pcoinsTip;
+
CBigNum bnCentSecond = 0; // coin age in the unit of cent-seconds
nCoinAge = 0;
{
nCoinAge = 0;
- CCoinsDB coindb("r");
- CCoinsViewDB view(coindb);
-
BOOST_FOREACH(const CTransaction& tx, vtx)
{
uint64 nTxCoinAge;
- if (tx.GetCoinAge(view, nTxCoinAge))
+ if (tx.GetCoinAge(nTxCoinAge))
nCoinAge += nTxCoinAge;
else
return false;
return false;
// New best
- if (pindexNew->nChainTrust > nBestChainTrust) {
- if (!IsInitialBlockDownload() || (pindexNew->nHeight % 1) == 0)
- if (!SetBestChain(pindexNew))
- return false;
- }
+ if (!SetBestChain(pindexNew))
+ return false;
if (pindexNew == pindexBest)
{
// Load block index
//
CChainDB chaindb("cr");
- CCoinsDB coinsdb("cr");
- if (!LoadBlockIndex(coinsdb, chaindb))
+ if (!LoadBlockIndex(chaindb))
return false;
chaindb.Close();
- coinsdb.Close();
//
// Init with genesis block
//
-bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv)
+bool static AlreadyHave(const CInv& inv)
{
switch (inv.type)
{
txInMap = mempool.exists(inv.hash);
}
return txInMap || mapOrphanTransactions.count(inv.hash) ||
- coinsdb.HaveCoins(inv.hash);
+ pcoinsTip->HaveCoins(inv.hash);
}
case MSG_BLOCK:
return mapBlockIndex.count(inv.hash) ||
break;
}
}
- CCoinsDB coinsdb("r");
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
{
const CInv &inv = vInv[nInv];
return true;
pfrom->AddInventoryKnown(inv);
- bool fAlreadyHave = AlreadyHave(coinsdb, inv);
+ bool fAlreadyHave = AlreadyHave(inv);
if (fDebug)
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
vector<uint256> vWorkQueue;
vector<uint256> vEraseQueue;
CDataStream vMsg(vRecv);
- CCoinsDB coinsdb("r");
CTransaction tx;
vRecv >> tx;
pfrom->AddInventoryKnown(inv);
bool fMissingInputs = false;
- if (tx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs))
+ if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{
SyncWithWallets(tx, NULL, true);
RelayTransaction(tx, inv.hash);
CTransaction& orphanTx = mapOrphanTransactions[orphanTxHash];
bool fMissingInputs2 = false;
- if (orphanTx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs2))
+ if (orphanTx.AcceptToMemoryPool(true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", orphanTxHash.ToString().substr(0,10).c_str());
SyncWithWallets(tx, NULL, true);
//
vector<CInv> vGetData;
int64 nNow = GetTime() * 1000000;
- CCoinsDB coinsdb("r");
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
{
const CInv& inv = (*pto->mapAskFor.begin()).second;
- if (!AlreadyHave(coinsdb, inv))
+ if (!AlreadyHave(inv))
{
if (fDebugNet)
printf("sending getdata: %s\n", inv.ToString().c_str());
bool CheckTransaction() const;
// Try to accept this transaction into the memory pool
- bool AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
- bool GetCoinAge(CCoinsView& inputs, uint64& nCoinAge) const; // Get transaction coin age
+ bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
+ bool GetCoinAge(uint64& nCoinAge) const; // Get transaction coin age
protected:
static CTxOut GetOutputFor(const CTxIn& input, CCoinsView& mapInputs);
};
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(CCoinsDB& txdb, bool fCheckInputs=true);
- bool AcceptToMemoryPool();
+ bool AcceptToMemoryPool(bool fCheckInputs=true);
};
std::map<uint256, CTransaction> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
- bool accept(CCoinsDB& coinsdb, CTransaction &tx,
- bool fCheckInputs, bool* pfMissingInputs);
+ bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs);
bool addUnchecked(const uint256& hash, CTransaction &tx);
bool remove(CTransaction &tx);
void clear();
// Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex);
+ virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
};
/** CCoinsView backed by another CCoinsView */
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn);
-};
-
-
-/** CCoinsView backed by a CCoinsDB */
-class CCoinsViewDB : public CCoinsView
-{
-protected:
- CCoinsDB &db;
-public:
- CCoinsViewDB(CCoinsDB &dbIn);
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
- CBlockIndex *GetBestBlock();
- bool SetBestBlock(CBlockIndex *pindex);
+ bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
};
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
bool HaveCoins(uint256 txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
+ bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
bool Flush();
+ unsigned int GetCacheSize();
};
/** CCoinsView that brings transactions from a memorypool into view.
bool HaveCoins(uint256 txid);
};
+extern CCoinsViewCache *pcoinsTip;
+
#endif
int64 nFees = 0;
{
LOCK2(cs_main, mempool.cs);
- CCoinsDB coinsdb("r");
- CCoinsViewDB viewdb(coinsdb);
- CCoinsViewCache view(viewdb);
+ CCoinsViewCache view(*pcoinsTip, true);
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
- CCoinsDB coinsdb("r"); // To fetch source txouts
- CCoinsViewDB coins(coinsdb);
-
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
strHTML += "<ul>";
COutPoint prevout = txin.prevout;
CCoins prev;
- if(coins.GetCoins(prevout.hash, prev))
+ if(pcoinsTip->GetCoins(prevout.hash, prev))
{
if (prevout.n < prev.vout.size())
{
Array transactions;
map<uint256, int64_t> setTxIndex;
int i = 0;
- CCoinsDB coindb("r");
- CCoinsViewDB viewdb(coindb);
- CCoinsViewCache view(viewdb);
+ CCoinsViewCache &view = *pcoinsTip;
BOOST_FOREACH (CTransaction& tx, pblock->vtx)
{
uint256 txHash = tx.GetHash();
CCoinsViewCache view(viewDummy);
{
LOCK(mempool.cs);
- CCoinsDB coinsdb("r");
- CCoinsViewDB viewDB(coinsdb);
- CCoinsViewMemPool viewMempool(viewDB, mempool);
+ CCoinsViewCache &viewChain = *pcoinsTip;
+ CCoinsViewMemPool viewMempool(viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
view.GetCoins(prevHash, coins); // this is certainly allowed to fail
}
- view.SetBackend(viewDummy); // switch back to avoid locking db/mempool too long
+ view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
}
// Add previous txouts given in the RPC call:
uint256 hashTx = tx.GetHash();
bool fHave = false;
+ CCoinsViewCache &view = *pcoinsTip;
CCoins existingCoins;
{
- CCoinsDB coinsdb("r");
- {
- CCoinsViewDB coinsviewDB(coinsdb);
- CCoinsViewMemPool coinsview(coinsviewDB, mempool);
- fHave = coinsview.GetCoins(hashTx, existingCoins);
- }
+ fHave = view.GetCoins(hashTx, existingCoins);
if (!fHave) {
// push to local node
- if (!tx.AcceptToMemoryPool(coinsdb))
+ if (!tx.AcceptToMemoryPool())
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
}
}
void CWallet::ReacceptWalletTransactions()
{
- CCoinsDB coinsdb("r");
bool fRepeat = true;
while (fRepeat)
{
CCoins coins;
bool fUpdated = false;
- bool fNotFound = coinsdb.ReadCoins(wtx.GetHash(), coins);
+ bool fNotFound = pcoinsTip->GetCoins(wtx.GetHash(), coins);
if (!fNotFound || wtx.GetDepthInMainChain() > 0)
{
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
{
// Re-accept any txes of ours that aren't already in a block
if (!wtx.IsCoinBase())
- wtx.AcceptWalletTransaction(coinsdb, false);
+ wtx.AcceptWalletTransaction(false);
}
}
if (fMissing)
}
}
-void CWalletTx::RelayWalletTransaction(CCoinsDB& coinsdb)
+void CWalletTx::RelayWalletTransaction()
{
+ CCoinsViewCache& coins = *pcoinsTip;
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
{
if (!tx.IsCoinBase())
{
uint256 hash = tx.GetHash();
- if (!coinsdb.HaveCoins(hash))
+ if (!coins.HaveCoins(hash))
RelayTransaction((CTransaction)tx, hash);
}
}
if (!IsCoinBase())
{
uint256 hash = GetHash();
- if (!coinsdb.HaveCoins(hash))
+ if (!coins.HaveCoins(hash))
{
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
RelayTransaction((CTransaction)*this, hash);
}
}
-void CWalletTx::RelayWalletTransaction()
-{
- CCoinsDB coinsdb("r");
- RelayWalletTransaction(coinsdb);
-}
-
void CWallet::ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
// Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n");
- CCoinsDB coinsdb("r");
{
LOCK(cs_wallet);
// Sort them in chronological order
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *item.second;
- wtx.RelayWalletTransaction(coinsdb);
+ wtx.RelayWalletTransaction();
}
}
}
if (setCoins.empty())
return false;
- CCoinsDB coinsdb("r");
- CCoinsViewDB view(coinsdb);
+ CCoinsViewCache &view = *pcoinsTip;
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
CCoins coins;
int64 nCredit = 0;
CScript scriptPubKeyKernel;
- CCoinsDB coinsdb("r");
- CCoinsViewDB view(coinsdb);
+ CCoinsViewCache &view = *pcoinsTip;
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
CCoins coins;
{
uint64 nCoinAge;
- CCoinsDB coindb("r");
- CCoinsViewDB view(coindb);
-
- if (!txNew.GetCoinAge(view, nCoinAge))
+ if (!txNew.GetCoinAge(nCoinAge))
return error("CreateCoinStake : failed to calculate coin age");
nCredit += GetProofOfStakeReward(nCoinAge, nBits, txNew.nTime);
}
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
vCoins.push_back(&(*it).second);
- CCoinsDB coinsdb("r");
+ CCoinsViewCache &view = *pcoinsTip;
BOOST_FOREACH(CWalletTx* pcoin, vCoins)
{
// Find the corresponding transaction index
CCoins coins;
- bool fNotFound = coinsdb.ReadCoins(pcoin->GetHash(), coins);
+ bool fNotFound = view.GetCoins(pcoin->GetHash(), coins);
for (unsigned int n=0; n < pcoin->vout.size(); n++)
{
void AddSupportingTransactions();
- bool AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs=true);
- bool AcceptWalletTransaction();
-
- void RelayWalletTransaction(CCoinsDB& coinsdb);
+ bool AcceptWalletTransaction(bool fCheckInputs=true);
void RelayWalletTransaction();
};