Batch block connection during IBD
During the initial block download (or -loadblock), delay connection of new blocks a bit, and perform them in a single action. This reduces the load on the database engine, as subsequent blocks often update an earlier block's transaction already.
This commit is contained in:
parent
450cbb0944
commit
ae8bfd12da
10 changed files with 183 additions and 171 deletions
89
src/db.cpp
89
src/db.cpp
|
@ -79,8 +79,8 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
|
||||||
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
|
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
|
||||||
dbenv.set_lg_bsize(1048576);
|
dbenv.set_lg_bsize(1048576);
|
||||||
dbenv.set_lg_max(10485760);
|
dbenv.set_lg_max(10485760);
|
||||||
dbenv.set_lk_max_locks(10000);
|
dbenv.set_lk_max_locks(40000);
|
||||||
dbenv.set_lk_max_objects(10000);
|
dbenv.set_lk_max_objects(40000);
|
||||||
dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
|
dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
|
||||||
dbenv.set_flags(DB_AUTO_COMMIT, 1);
|
dbenv.set_flags(DB_AUTO_COMMIT, 1);
|
||||||
dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
|
dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
|
||||||
|
@ -279,14 +279,10 @@ static bool IsChainFile(std::string strFile)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDB::Close()
|
void CDB::Flush()
|
||||||
{
|
{
|
||||||
if (!pdb)
|
|
||||||
return;
|
|
||||||
if (activeTxn)
|
if (activeTxn)
|
||||||
activeTxn->abort();
|
return;
|
||||||
activeTxn = NULL;
|
|
||||||
pdb = NULL;
|
|
||||||
|
|
||||||
// Flush database activity from memory pool to disk log
|
// Flush database activity from memory pool to disk log
|
||||||
unsigned int nMinutes = 0;
|
unsigned int nMinutes = 0;
|
||||||
|
@ -298,6 +294,18 @@ void CDB::Close()
|
||||||
nMinutes = 5;
|
nMinutes = 5;
|
||||||
|
|
||||||
bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
|
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);
|
LOCK(bitdb.cs_db);
|
||||||
|
@ -537,6 +545,42 @@ bool CChainDB::ReadLastBlockFile(int &nFile) {
|
||||||
return Read('l', 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)
|
CBlockIndex static * InsertBlockIndex(uint256 hash)
|
||||||
{
|
{
|
||||||
if (hash == 0)
|
if (hash == 0)
|
||||||
|
@ -557,7 +601,7 @@ CBlockIndex static * InsertBlockIndex(uint256 hash)
|
||||||
return pindexNew;
|
return pindexNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
|
bool LoadBlockIndex(CChainDB &chaindb)
|
||||||
{
|
{
|
||||||
if (!chaindb.LoadBlockIndexGuts())
|
if (!chaindb.LoadBlockIndexGuts())
|
||||||
return false;
|
return false;
|
||||||
|
@ -587,26 +631,23 @@ bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
|
||||||
printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
|
printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
|
||||||
|
|
||||||
// Load hashBestChain pointer to end of best chain
|
// Load hashBestChain pointer to end of best chain
|
||||||
if (!coindb.ReadHashBestChain(hashBestChain))
|
pindexBest = pcoinsTip->GetBestBlock();
|
||||||
|
if (pindexBest == NULL)
|
||||||
{
|
{
|
||||||
if (pindexGenesisBlock == NULL)
|
if (pindexGenesisBlock == NULL)
|
||||||
return true;
|
return true;
|
||||||
return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
|
return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
|
||||||
}
|
}
|
||||||
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
|
hashBestChain = pindexBest->GetBlockHash();
|
||||||
if (it == mapBlockIndex.end()) {
|
nBestHeight = pindexBest->nHeight;
|
||||||
return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
|
bnBestChainWork = pindexBest->bnChainWork;
|
||||||
} else {
|
|
||||||
// set 'next' pointers in best chain
|
// set 'next' pointers in best chain
|
||||||
CBlockIndex *pindex = it->second;
|
CBlockIndex *pindex = pindexBest;
|
||||||
while(pindex != NULL && pindex->pprev != NULL) {
|
while(pindex != NULL && pindex->pprev != NULL) {
|
||||||
CBlockIndex *pindexPrev = pindex->pprev;
|
CBlockIndex *pindexPrev = pindex->pprev;
|
||||||
pindexPrev->pnext = pindex;
|
pindexPrev->pnext = pindex;
|
||||||
pindex = pindexPrev;
|
pindex = pindexPrev;
|
||||||
}
|
|
||||||
pindexBest = it->second;
|
|
||||||
nBestHeight = pindexBest->nHeight;
|
|
||||||
bnBestChainWork = pindexBest->bnChainWork;
|
|
||||||
}
|
}
|
||||||
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
|
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
|
||||||
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
|
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
|
||||||
|
|
20
src/db.h
20
src/db.h
|
@ -102,6 +102,7 @@ protected:
|
||||||
explicit CDB(const char* pszFile, const char* pszMode="r+");
|
explicit CDB(const char* pszFile, const char* pszMode="r+");
|
||||||
~CDB() { Close(); }
|
~CDB() { Close(); }
|
||||||
public:
|
public:
|
||||||
|
void Flush();
|
||||||
void Close();
|
void Close();
|
||||||
private:
|
private:
|
||||||
CDB(const CDB&);
|
CDB(const CDB&);
|
||||||
|
@ -330,6 +331,23 @@ public:
|
||||||
bool WriteHashBestChain(uint256 hashBestChain);
|
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) */
|
/** Access to the block database (chain.dat) */
|
||||||
class CChainDB : public CDB
|
class CChainDB : public CDB
|
||||||
{
|
{
|
||||||
|
@ -350,7 +368,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
bool LoadBlockIndex(CCoinsDB &coinsdb, CChainDB &chaindb);
|
bool LoadBlockIndex(CChainDB &chaindb);
|
||||||
|
|
||||||
|
|
||||||
/** Access to the (IP) address database (peers.dat) */
|
/** Access to the (IP) address database (peers.dat) */
|
||||||
|
|
12
src/init.cpp
12
src/init.cpp
|
@ -50,6 +50,8 @@ void StartShutdown()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CCoinsViewDB *pcoinsdbview;
|
||||||
|
|
||||||
void Shutdown(void* parg)
|
void Shutdown(void* parg)
|
||||||
{
|
{
|
||||||
static CCriticalSection cs_Shutdown;
|
static CCriticalSection cs_Shutdown;
|
||||||
|
@ -74,6 +76,12 @@ void Shutdown(void* parg)
|
||||||
nTransactionsUpdated++;
|
nTransactionsUpdated++;
|
||||||
bitdb.Flush(false);
|
bitdb.Flush(false);
|
||||||
StopNode();
|
StopNode();
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
pcoinsTip->Flush();
|
||||||
|
delete pcoinsTip;
|
||||||
|
delete pcoinsdbview;
|
||||||
|
}
|
||||||
bitdb.Flush(true);
|
bitdb.Flush(true);
|
||||||
boost::filesystem::remove(GetPidFile());
|
boost::filesystem::remove(GetPidFile());
|
||||||
UnregisterWallet(pwalletMain);
|
UnregisterWallet(pwalletMain);
|
||||||
|
@ -298,6 +306,7 @@ std::string HelpMessage()
|
||||||
return strUsage;
|
return strUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Initialize bitcoin.
|
/** Initialize bitcoin.
|
||||||
* @pre Parameters should be parsed and config file should be read.
|
* @pre Parameters should be parsed and config file should be read.
|
||||||
*/
|
*/
|
||||||
|
@ -641,6 +650,9 @@ bool AppInit2()
|
||||||
uiInterface.InitMessage(_("Loading block index..."));
|
uiInterface.InitMessage(_("Loading block index..."));
|
||||||
printf("Loading block index...\n");
|
printf("Loading block index...\n");
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
|
pcoinsdbview = new CCoinsViewDB();
|
||||||
|
pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
|
||||||
|
|
||||||
if (!LoadBlockIndex())
|
if (!LoadBlockIndex())
|
||||||
return InitError(_("Error loading blkindex.dat"));
|
return InitError(_("Error loading blkindex.dat"));
|
||||||
|
|
||||||
|
|
150
src/main.cpp
150
src/main.cpp
|
@ -168,6 +168,7 @@ bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; }
|
||||||
bool CCoinsView::HaveCoins(uint256 txid) { return false; }
|
bool CCoinsView::HaveCoins(uint256 txid) { return false; }
|
||||||
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
|
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
|
||||||
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
|
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) { }
|
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
|
||||||
bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
|
bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
|
||||||
|
@ -176,13 +177,7 @@ bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); }
|
||||||
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
|
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
|
||||||
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
|
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
|
||||||
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
|
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
|
||||||
|
bool CCoinsViewBacked::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); }
|
||||||
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()); }
|
|
||||||
|
|
||||||
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
|
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
|
||||||
|
|
||||||
|
@ -218,18 +213,24 @@ bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCoinsViewCache::Flush() {
|
bool CCoinsViewCache::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
|
||||||
for (std::map<uint256,CCoins>::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
|
for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
|
||||||
if (!base->SetCoins(it->first, it->second))
|
cacheCoins[it->first] = it->second;
|
||||||
return false;
|
pindexTip = pindex;
|
||||||
}
|
|
||||||
if (!base->SetBestBlock(pindexTip))
|
|
||||||
return false;
|
|
||||||
cacheCoins.clear();
|
|
||||||
pindexTip = NULL;
|
|
||||||
return true;
|
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.
|
/** CCoinsView that brings transactions from a memorypool into view.
|
||||||
It does not check for spendings by memory pool transactions. */
|
It does not check for spendings by memory pool transactions. */
|
||||||
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
|
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
|
||||||
|
@ -249,7 +250,7 @@ bool CCoinsViewMemPool::HaveCoins(uint256 txid) {
|
||||||
return mempool.exists(txid) || base->HaveCoins(txid);
|
return mempool.exists(txid) || base->HaveCoins(txid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCoinsViewCache *pcoinsTip = NULL;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -450,9 +451,8 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
|
||||||
CBlock blockTmp;
|
CBlock blockTmp;
|
||||||
|
|
||||||
if (pblock == NULL) {
|
if (pblock == NULL) {
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
CCoins coins;
|
CCoins coins;
|
||||||
if (coinsdb.ReadCoins(GetHash(), coins)) {
|
if (pcoinsTip->GetCoins(GetHash(), coins)) {
|
||||||
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
|
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
|
||||||
if (pindex) {
|
if (pindex) {
|
||||||
if (!blockTmp.ReadFromDisk(pindex))
|
if (!blockTmp.ReadFromDisk(pindex))
|
||||||
|
@ -609,7 +609,7 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs,
|
bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
|
||||||
bool* pfMissingInputs)
|
bool* pfMissingInputs)
|
||||||
{
|
{
|
||||||
if (pfMissingInputs)
|
if (pfMissingInputs)
|
||||||
|
@ -668,9 +668,7 @@ bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs,
|
||||||
|
|
||||||
if (fCheckInputs)
|
if (fCheckInputs)
|
||||||
{
|
{
|
||||||
CCoinsViewDB viewDB(coinsdb);
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
CCoinsViewMemPool viewMemPool(viewDB, mempool);
|
|
||||||
CCoinsViewCache view(viewMemPool);
|
|
||||||
|
|
||||||
// do we already have it?
|
// do we already have it?
|
||||||
if (view.HaveCoins(hash))
|
if (view.HaveCoins(hash))
|
||||||
|
@ -758,9 +756,9 @@ bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs,
|
||||||
return true;
|
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 CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
|
||||||
|
@ -849,31 +847,24 @@ int CMerkleTx::GetBlocksToMaturity() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CMerkleTx::AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs)
|
bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs)
|
||||||
{
|
{
|
||||||
if (fClient)
|
if (fClient)
|
||||||
{
|
{
|
||||||
if (!IsInMainChain() && !ClientCheckInputs())
|
if (!IsInMainChain() && !ClientCheckInputs())
|
||||||
return false;
|
return false;
|
||||||
return CTransaction::AcceptToMemoryPool(coinsdb, false);
|
return CTransaction::AcceptToMemoryPool(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return CTransaction::AcceptToMemoryPool(coinsdb, fCheckInputs);
|
return CTransaction::AcceptToMemoryPool(fCheckInputs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMerkleTx::AcceptToMemoryPool()
|
|
||||||
|
|
||||||
|
bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
|
||||||
{
|
{
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
return AcceptToMemoryPool(coinsdb);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
|
|
||||||
{
|
|
||||||
|
|
||||||
{
|
{
|
||||||
LOCK(mempool.cs);
|
LOCK(mempool.cs);
|
||||||
// Add previous supporting transactions first
|
// Add previous supporting transactions first
|
||||||
|
@ -882,20 +873,15 @@ bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
uint256 hash = tx.GetHash();
|
uint256 hash = tx.GetHash();
|
||||||
if (!mempool.exists(hash) && !coinsdb.HaveCoins(hash))
|
if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash))
|
||||||
tx.AcceptToMemoryPool(coinsdb, fCheckInputs);
|
tx.AcceptToMemoryPool(fCheckInputs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AcceptToMemoryPool(coinsdb, fCheckInputs);
|
return AcceptToMemoryPool(fCheckInputs);
|
||||||
}
|
}
|
||||||
return false;
|
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
|
// 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)
|
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
|
||||||
|
@ -915,8 +901,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
|
||||||
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
|
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
|
||||||
int nHeight = -1;
|
int nHeight = -1;
|
||||||
{
|
{
|
||||||
CCoinsDB coindb("r");
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
CCoinsViewDB view(coindb);
|
|
||||||
CCoins coins;
|
CCoins coins;
|
||||||
if (view.GetCoins(hash, coins))
|
if (view.GetCoins(hash, coins))
|
||||||
nHeight = coins.nHeight;
|
nHeight = coins.nHeight;
|
||||||
|
@ -1565,18 +1550,15 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
|
||||||
|
|
||||||
bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
||||||
{
|
{
|
||||||
// if this functions exits prematurely, the transaction is aborted
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
CCoinsDB coinsdb;
|
|
||||||
if (!coinsdb.TxnBegin())
|
|
||||||
return error("SetBestChain() : TxnBegin failed");
|
|
||||||
|
|
||||||
// special case for attaching the genesis block
|
// special case for attaching the genesis block
|
||||||
// note that no ConnectBlock is called, so its coinbase output is non-spendable
|
// note that no ConnectBlock is called, so its coinbase output is non-spendable
|
||||||
if (pindexGenesisBlock == NULL && pindexNew->GetBlockHash() == hashGenesisBlock)
|
if (pindexGenesisBlock == NULL && pindexNew->GetBlockHash() == hashGenesisBlock)
|
||||||
{
|
{
|
||||||
coinsdb.WriteHashBestChain(pindexNew->GetBlockHash());
|
view.SetBestBlock(pindexNew);
|
||||||
if (!coinsdb.TxnCommit())
|
if (!view.Flush())
|
||||||
return error("SetBestChain() : TxnCommit failed");
|
return false;
|
||||||
pindexGenesisBlock = pindexNew;
|
pindexGenesisBlock = pindexNew;
|
||||||
pindexBest = pindexNew;
|
pindexBest = pindexNew;
|
||||||
hashBestChain = pindexNew->GetBlockHash();
|
hashBestChain = pindexNew->GetBlockHash();
|
||||||
|
@ -1585,10 +1567,6 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create cached view to the coins database
|
|
||||||
CCoinsViewDB viewDB(coinsdb);
|
|
||||||
CCoinsViewCache view(viewDB);
|
|
||||||
|
|
||||||
// Find the fork (typically, there is none)
|
// Find the fork (typically, there is none)
|
||||||
CBlockIndex* pfork = view.GetBestBlock();
|
CBlockIndex* pfork = view.GetBestBlock();
|
||||||
CBlockIndex* plonger = pindexNew;
|
CBlockIndex* plonger = pindexNew;
|
||||||
|
@ -1625,8 +1603,11 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (!block.ReadFromDisk(pindex))
|
if (!block.ReadFromDisk(pindex))
|
||||||
return error("SetBestBlock() : ReadFromDisk for disconnect failed");
|
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());
|
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
|
// Queue memory transactions to resurrect
|
||||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
|
@ -1646,10 +1627,13 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
||||||
return error("SetBestBlock() : ReadFromDisk for connect failed");
|
return error("SetBestBlock() : ReadFromDisk for connect failed");
|
||||||
pblock = █
|
pblock = █
|
||||||
}
|
}
|
||||||
if (!pblock->ConnectBlock(pindex, view)) {
|
CCoinsViewCache viewTemp(view, true);
|
||||||
|
if (!pblock->ConnectBlock(pindex, viewTemp)) {
|
||||||
InvalidChainFound(pindexNew);
|
InvalidChainFound(pindexNew);
|
||||||
return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
|
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
|
// Queue memory transactions to delete
|
||||||
BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
|
BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
|
||||||
|
@ -1657,11 +1641,10 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure it's successfully written to disk before changing memory structure
|
// Make sure it's successfully written to disk before changing memory structure
|
||||||
if (!view.Flush())
|
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||||
return error("SetBestBlock() : failed to write coin changes");
|
if (!fIsInitialDownload || view.GetCacheSize()>5000)
|
||||||
if (!coinsdb.TxnCommit())
|
if (!view.Flush())
|
||||||
return error("SetBestBlock() : TxnCommit failed");
|
return false;
|
||||||
coinsdb.Close();
|
|
||||||
|
|
||||||
// At this point, all changes have been done to the database.
|
// At this point, all changes have been done to the database.
|
||||||
// Proceed by updating the memory structures.
|
// Proceed by updating the memory structures.
|
||||||
|
@ -1678,14 +1661,13 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
|
||||||
|
|
||||||
// Resurrect memory transactions that were in the disconnected branch
|
// Resurrect memory transactions that were in the disconnected branch
|
||||||
BOOST_FOREACH(CTransaction& tx, vResurrect)
|
BOOST_FOREACH(CTransaction& tx, vResurrect)
|
||||||
tx.AcceptToMemoryPool(coinsdb, false);
|
tx.AcceptToMemoryPool(false);
|
||||||
|
|
||||||
// Delete redundant memory transactions that are in the connected branch
|
// Delete redundant memory transactions that are in the connected branch
|
||||||
BOOST_FOREACH(CTransaction& tx, vDelete)
|
BOOST_FOREACH(CTransaction& tx, vDelete)
|
||||||
mempool.remove(tx);
|
mempool.remove(tx);
|
||||||
|
|
||||||
// Update best block in wallet (so we can detect restored wallets)
|
// Update best block in wallet (so we can detect restored wallets)
|
||||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
|
||||||
if (!fIsInitialDownload)
|
if (!fIsInitialDownload)
|
||||||
{
|
{
|
||||||
const CBlockLocator locator(pindexNew);
|
const CBlockLocator locator(pindexNew);
|
||||||
|
@ -1765,11 +1747,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// New best
|
// New best
|
||||||
if (pindexNew->bnChainWork > bnBestChainWork) {
|
if (!SetBestChain(pindexNew))
|
||||||
if (!IsInitialBlockDownload() || (pindexNew->nHeight % 1) == 0)
|
return false;
|
||||||
if (!SetBestChain(pindexNew))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pindexNew == pindexBest)
|
if (pindexNew == pindexBest)
|
||||||
{
|
{
|
||||||
|
@ -2169,11 +2148,9 @@ bool LoadBlockIndex(bool fAllowNew)
|
||||||
// Load block index
|
// Load block index
|
||||||
//
|
//
|
||||||
CChainDB chaindb("cr");
|
CChainDB chaindb("cr");
|
||||||
CCoinsDB coinsdb("cr");
|
if (!LoadBlockIndex(chaindb))
|
||||||
if (!LoadBlockIndex(coinsdb, chaindb))
|
|
||||||
return false;
|
return false;
|
||||||
chaindb.Close();
|
chaindb.Close();
|
||||||
coinsdb.Close();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Init with genesis block
|
// Init with genesis block
|
||||||
|
@ -2492,7 +2469,7 @@ string GetWarnings(string strFor)
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv)
|
bool static AlreadyHave(const CInv& inv)
|
||||||
{
|
{
|
||||||
switch (inv.type)
|
switch (inv.type)
|
||||||
{
|
{
|
||||||
|
@ -2504,7 +2481,7 @@ bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv)
|
||||||
txInMap = mempool.exists(inv.hash);
|
txInMap = mempool.exists(inv.hash);
|
||||||
}
|
}
|
||||||
return txInMap || mapOrphanTransactions.count(inv.hash) ||
|
return txInMap || mapOrphanTransactions.count(inv.hash) ||
|
||||||
coinsdb.HaveCoins(inv.hash);
|
pcoinsTip->HaveCoins(inv.hash);
|
||||||
}
|
}
|
||||||
case MSG_BLOCK:
|
case MSG_BLOCK:
|
||||||
return mapBlockIndex.count(inv.hash) ||
|
return mapBlockIndex.count(inv.hash) ||
|
||||||
|
@ -2748,7 +2725,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
|
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
|
||||||
{
|
{
|
||||||
const CInv &inv = vInv[nInv];
|
const CInv &inv = vInv[nInv];
|
||||||
|
@ -2757,7 +2733,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
return true;
|
return true;
|
||||||
pfrom->AddInventoryKnown(inv);
|
pfrom->AddInventoryKnown(inv);
|
||||||
|
|
||||||
bool fAlreadyHave = AlreadyHave(coinsdb, inv);
|
bool fAlreadyHave = AlreadyHave(inv);
|
||||||
if (fDebug)
|
if (fDebug)
|
||||||
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
|
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
|
||||||
|
|
||||||
|
@ -2929,7 +2905,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
vector<uint256> vWorkQueue;
|
vector<uint256> vWorkQueue;
|
||||||
vector<uint256> vEraseQueue;
|
vector<uint256> vEraseQueue;
|
||||||
CDataStream vMsg(vRecv);
|
CDataStream vMsg(vRecv);
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
vRecv >> tx;
|
vRecv >> tx;
|
||||||
|
|
||||||
|
@ -2937,7 +2912,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
pfrom->AddInventoryKnown(inv);
|
pfrom->AddInventoryKnown(inv);
|
||||||
|
|
||||||
bool fMissingInputs = false;
|
bool fMissingInputs = false;
|
||||||
if (tx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs))
|
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
|
||||||
{
|
{
|
||||||
SyncWithWallets(tx, NULL, true);
|
SyncWithWallets(tx, NULL, true);
|
||||||
RelayMessage(inv, vMsg);
|
RelayMessage(inv, vMsg);
|
||||||
|
@ -2959,7 +2934,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||||
CInv inv(MSG_TX, tx.GetHash());
|
CInv inv(MSG_TX, tx.GetHash());
|
||||||
bool fMissingInputs2 = false;
|
bool fMissingInputs2 = false;
|
||||||
|
|
||||||
if (tx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs2))
|
if (tx.AcceptToMemoryPool(true, &fMissingInputs2))
|
||||||
{
|
{
|
||||||
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
|
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
|
||||||
SyncWithWallets(tx, NULL, true);
|
SyncWithWallets(tx, NULL, true);
|
||||||
|
@ -3407,11 +3382,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||||
//
|
//
|
||||||
vector<CInv> vGetData;
|
vector<CInv> vGetData;
|
||||||
int64 nNow = GetTime() * 1000000;
|
int64 nNow = GetTime() * 1000000;
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
|
while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
|
||||||
{
|
{
|
||||||
const CInv& inv = (*pto->mapAskFor.begin()).second;
|
const CInv& inv = (*pto->mapAskFor.begin()).second;
|
||||||
if (!AlreadyHave(coinsdb, inv))
|
if (!AlreadyHave(inv))
|
||||||
{
|
{
|
||||||
if (fDebugNet)
|
if (fDebugNet)
|
||||||
printf("sending getdata: %s\n", inv.ToString().c_str());
|
printf("sending getdata: %s\n", inv.ToString().c_str());
|
||||||
|
@ -3621,9 +3595,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
|
||||||
int64 nFees = 0;
|
int64 nFees = 0;
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, mempool.cs);
|
LOCK2(cs_main, mempool.cs);
|
||||||
CCoinsDB coinsdb("r");
|
CCoinsViewCache view(*pcoinsTip, true);
|
||||||
CCoinsViewDB viewdb(coinsdb);
|
|
||||||
CCoinsViewCache view(viewdb);
|
|
||||||
|
|
||||||
// Priority order to process transactions
|
// Priority order to process transactions
|
||||||
list<COrphan> vOrphan; // list memory doesn't move
|
list<COrphan> vOrphan; // list memory doesn't move
|
||||||
|
@ -3811,7 +3783,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
|
||||||
CBlockIndex indexDummy(*pblock);
|
CBlockIndex indexDummy(*pblock);
|
||||||
indexDummy.pprev = pindexPrev;
|
indexDummy.pprev = pindexPrev;
|
||||||
indexDummy.nHeight = pindexPrev->nHeight + 1;
|
indexDummy.nHeight = pindexPrev->nHeight + 1;
|
||||||
CCoinsViewCache viewNew(viewdb);
|
CCoinsViewCache viewNew(*pcoinsTip, true);
|
||||||
if (!pblock->ConnectBlock(&indexDummy, viewNew, true))
|
if (!pblock->ConnectBlock(&indexDummy, viewNew, true))
|
||||||
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
|
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
|
||||||
}
|
}
|
||||||
|
|
30
src/main.h
30
src/main.h
|
@ -583,7 +583,7 @@ public:
|
||||||
bool CheckTransaction() const;
|
bool CheckTransaction() const;
|
||||||
|
|
||||||
// Try to accept this transaction into the memory pool
|
// Try to accept this transaction into the memory pool
|
||||||
bool AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
|
bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static CTxOut GetOutputFor(const CTxIn& input, CCoinsView& mapInputs);
|
static CTxOut GetOutputFor(const CTxIn& input, CCoinsView& mapInputs);
|
||||||
|
@ -682,6 +682,7 @@ public:
|
||||||
|
|
||||||
bool WriteToDisk(CDiskBlockPos &pos)
|
bool WriteToDisk(CDiskBlockPos &pos)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Open history file to append
|
// Open history file to append
|
||||||
CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
|
CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
|
||||||
if (!fileout)
|
if (!fileout)
|
||||||
|
@ -995,8 +996,7 @@ public:
|
||||||
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
|
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
|
||||||
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
|
bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
|
||||||
int GetBlocksToMaturity() const;
|
int GetBlocksToMaturity() const;
|
||||||
bool AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs=true);
|
bool AcceptToMemoryPool(bool fCheckInputs=true);
|
||||||
bool AcceptToMemoryPool();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1676,8 +1676,7 @@ public:
|
||||||
std::map<uint256, CTransaction> mapTx;
|
std::map<uint256, CTransaction> mapTx;
|
||||||
std::map<COutPoint, CInPoint> mapNextTx;
|
std::map<COutPoint, CInPoint> mapNextTx;
|
||||||
|
|
||||||
bool accept(CCoinsDB& coinsdb, CTransaction &tx,
|
bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs);
|
||||||
bool fCheckInputs, bool* pfMissingInputs);
|
|
||||||
bool addUnchecked(const uint256& hash, CTransaction &tx);
|
bool addUnchecked(const uint256& hash, CTransaction &tx);
|
||||||
bool remove(CTransaction &tx);
|
bool remove(CTransaction &tx);
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -1722,6 +1721,7 @@ public:
|
||||||
|
|
||||||
// Modify the currently active block index
|
// Modify the currently active block index
|
||||||
virtual bool SetBestBlock(CBlockIndex *pindex);
|
virtual bool SetBestBlock(CBlockIndex *pindex);
|
||||||
|
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** CCoinsView backed by another CCoinsView */
|
/** CCoinsView backed by another CCoinsView */
|
||||||
|
@ -1738,21 +1738,7 @@ public:
|
||||||
CBlockIndex *GetBestBlock();
|
CBlockIndex *GetBestBlock();
|
||||||
bool SetBestBlock(CBlockIndex *pindex);
|
bool SetBestBlock(CBlockIndex *pindex);
|
||||||
void SetBackend(CCoinsView &viewIn);
|
void SetBackend(CCoinsView &viewIn);
|
||||||
};
|
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
|
||||||
|
|
||||||
|
|
||||||
/** 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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
|
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
|
||||||
|
@ -1769,7 +1755,9 @@ public:
|
||||||
bool HaveCoins(uint256 txid);
|
bool HaveCoins(uint256 txid);
|
||||||
CBlockIndex *GetBestBlock();
|
CBlockIndex *GetBestBlock();
|
||||||
bool SetBestBlock(CBlockIndex *pindex);
|
bool SetBestBlock(CBlockIndex *pindex);
|
||||||
|
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
|
||||||
bool Flush();
|
bool Flush();
|
||||||
|
unsigned int GetCacheSize();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** CCoinsView that brings transactions from a memorypool into view.
|
/** CCoinsView that brings transactions from a memorypool into view.
|
||||||
|
@ -1785,4 +1773,6 @@ public:
|
||||||
bool HaveCoins(uint256 txid);
|
bool HaveCoins(uint256 txid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern CCoinsViewCache *pcoinsTip;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -234,9 +234,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||||
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
||||||
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
|
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
|
||||||
|
|
||||||
CCoinsDB coindb("r"); // To fetch source txouts
|
|
||||||
CCoinsViewDB coins(coindb);
|
|
||||||
|
|
||||||
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
|
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
|
||||||
strHTML += "<ul>";
|
strHTML += "<ul>";
|
||||||
|
|
||||||
|
@ -247,7 +244,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||||
COutPoint prevout = txin.prevout;
|
COutPoint prevout = txin.prevout;
|
||||||
|
|
||||||
CCoins prev;
|
CCoins prev;
|
||||||
if(coins.GetCoins(prevout.hash, prev))
|
if(pcoinsTip->GetCoins(prevout.hash, prev))
|
||||||
{
|
{
|
||||||
if (prevout.n < prev.vout.size())
|
if (prevout.n < prev.vout.size())
|
||||||
{
|
{
|
||||||
|
|
|
@ -281,9 +281,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
||||||
Array transactions;
|
Array transactions;
|
||||||
map<uint256, int64_t> setTxIndex;
|
map<uint256, int64_t> setTxIndex;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
CCoinsDB coindb("r");
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
CCoinsViewDB viewdb(coindb);
|
|
||||||
CCoinsViewCache view(viewdb);
|
|
||||||
BOOST_FOREACH (CTransaction& tx, pblock->vtx)
|
BOOST_FOREACH (CTransaction& tx, pblock->vtx)
|
||||||
{
|
{
|
||||||
uint256 txHash = tx.GetHash();
|
uint256 txHash = tx.GetHash();
|
||||||
|
|
|
@ -339,9 +339,8 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||||
CCoinsViewCache view(viewDummy);
|
CCoinsViewCache view(viewDummy);
|
||||||
{
|
{
|
||||||
LOCK(mempool.cs);
|
LOCK(mempool.cs);
|
||||||
CCoinsDB coinsdb("r");
|
CCoinsViewCache &viewChain = *pcoinsTip;
|
||||||
CCoinsViewDB viewDB(coinsdb);
|
CCoinsViewMemPool viewMempool(viewChain, mempool);
|
||||||
CCoinsViewMemPool viewMempool(viewDB, mempool);
|
|
||||||
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
|
BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
|
||||||
|
@ -350,7 +349,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||||
view.GetCoins(prevHash, coins); // this is certainly allowed to fail
|
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:
|
// Add previous txouts given in the RPC call:
|
||||||
|
@ -502,17 +501,13 @@ Value sendrawtransaction(const Array& params, bool fHelp)
|
||||||
uint256 hashTx = tx.GetHash();
|
uint256 hashTx = tx.GetHash();
|
||||||
|
|
||||||
bool fHave = false;
|
bool fHave = false;
|
||||||
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
CCoins existingCoins;
|
CCoins existingCoins;
|
||||||
{
|
{
|
||||||
CCoinsDB coinsdb("r");
|
fHave = view.GetCoins(hashTx, existingCoins);
|
||||||
{
|
|
||||||
CCoinsViewDB coinsviewDB(coinsdb);
|
|
||||||
CCoinsViewMemPool coinsview(coinsviewDB, mempool);
|
|
||||||
fHave = coinsview.GetCoins(hashTx, existingCoins);
|
|
||||||
}
|
|
||||||
if (!fHave) {
|
if (!fHave) {
|
||||||
// push to local node
|
// push to local node
|
||||||
if (!tx.AcceptToMemoryPool(coinsdb))
|
if (!tx.AcceptToMemoryPool())
|
||||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -767,7 +767,6 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||||
|
|
||||||
void CWallet::ReacceptWalletTransactions()
|
void CWallet::ReacceptWalletTransactions()
|
||||||
{
|
{
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
bool fRepeat = true;
|
bool fRepeat = true;
|
||||||
while (fRepeat)
|
while (fRepeat)
|
||||||
{
|
{
|
||||||
|
@ -782,7 +781,7 @@ void CWallet::ReacceptWalletTransactions()
|
||||||
|
|
||||||
CCoins coins;
|
CCoins coins;
|
||||||
bool fUpdated = false;
|
bool fUpdated = false;
|
||||||
bool fNotFound = coinsdb.ReadCoins(wtx.GetHash(), coins);
|
bool fNotFound = pcoinsTip->GetCoins(wtx.GetHash(), coins);
|
||||||
if (!fNotFound || wtx.GetDepthInMainChain() > 0)
|
if (!fNotFound || wtx.GetDepthInMainChain() > 0)
|
||||||
{
|
{
|
||||||
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
||||||
|
@ -808,7 +807,7 @@ void CWallet::ReacceptWalletTransactions()
|
||||||
{
|
{
|
||||||
// Re-accept any txes of ours that aren't already in a block
|
// Re-accept any txes of ours that aren't already in a block
|
||||||
if (!wtx.IsCoinBase())
|
if (!wtx.IsCoinBase())
|
||||||
wtx.AcceptWalletTransaction(coinsdb, false);
|
wtx.AcceptWalletTransaction(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fMissing)
|
if (fMissing)
|
||||||
|
@ -820,21 +819,22 @@ void CWallet::ReacceptWalletTransactions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWalletTx::RelayWalletTransaction(CCoinsDB& coinsdb)
|
void CWalletTx::RelayWalletTransaction()
|
||||||
{
|
{
|
||||||
|
CCoinsViewCache& coins = *pcoinsTip;
|
||||||
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
|
BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
|
||||||
{
|
{
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
uint256 hash = tx.GetHash();
|
uint256 hash = tx.GetHash();
|
||||||
if (!coinsdb.HaveCoins(hash))
|
if (!coins.HaveCoins(hash))
|
||||||
RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
|
RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!IsCoinBase())
|
if (!IsCoinBase())
|
||||||
{
|
{
|
||||||
uint256 hash = GetHash();
|
uint256 hash = GetHash();
|
||||||
if (!coinsdb.HaveCoins(hash))
|
if (!coins.HaveCoins(hash))
|
||||||
{
|
{
|
||||||
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
|
printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
|
||||||
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
|
RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
|
||||||
|
@ -842,12 +842,6 @@ void CWalletTx::RelayWalletTransaction(CCoinsDB& coinsdb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWalletTx::RelayWalletTransaction()
|
|
||||||
{
|
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
RelayWalletTransaction(coinsdb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CWallet::ResendWalletTransactions()
|
void CWallet::ResendWalletTransactions()
|
||||||
{
|
{
|
||||||
// Do this infrequently and randomly to avoid giving away
|
// Do this infrequently and randomly to avoid giving away
|
||||||
|
@ -868,7 +862,6 @@ void CWallet::ResendWalletTransactions()
|
||||||
|
|
||||||
// Rebroadcast any of our txes that aren't in a block yet
|
// Rebroadcast any of our txes that aren't in a block yet
|
||||||
printf("ResendWalletTransactions()\n");
|
printf("ResendWalletTransactions()\n");
|
||||||
CCoinsDB coinsdb("r");
|
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
// Sort them in chronological order
|
// Sort them in chronological order
|
||||||
|
@ -884,7 +877,7 @@ void CWallet::ResendWalletTransactions()
|
||||||
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
|
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
|
||||||
{
|
{
|
||||||
CWalletTx& wtx = *item.second;
|
CWalletTx& wtx = *item.second;
|
||||||
wtx.RelayWalletTransaction(coinsdb);
|
wtx.RelayWalletTransaction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -659,11 +659,7 @@ public:
|
||||||
int GetRequestCount() const;
|
int GetRequestCount() const;
|
||||||
|
|
||||||
void AddSupportingTransactions();
|
void AddSupportingTransactions();
|
||||||
|
bool AcceptWalletTransaction(bool fCheckInputs=true);
|
||||||
bool AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs=true);
|
|
||||||
bool AcceptWalletTransaction();
|
|
||||||
|
|
||||||
void RelayWalletTransaction(CCoinsDB& coinsdb);
|
|
||||||
void RelayWalletTransaction();
|
void RelayWalletTransaction();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue