Skip to content
This repository has been archived by the owner on Feb 1, 2021. It is now read-only.

Commit

Permalink
guard orphanmaps with cs_orphans, guard block disk access with cs_blo…
Browse files Browse the repository at this point in the history
…ckstorage (#199)

* add cs_orphans to guard maporphantx and maporphantxbyprev

* add cs_blockstorage to guard disk access for block files

* add globals.cpp for global vars that have construction/destruction deps

* add sync point for wallet.pay test
  • Loading branch information
Greg-Griffith committed Jun 1, 2019
1 parent c305fce commit eacea89
Show file tree
Hide file tree
Showing 21 changed files with 307 additions and 221 deletions.
15 changes: 15 additions & 0 deletions qa/rpc-tests/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,21 @@ class NoConfigValue:
def __init__(self):
pass

def waitFor(timeout, fn, onError="timeout in waitFor", sleepAmt=1.0):
""" Repeatedly calls fn while it returns None, raising an assert after timeout. If fn returns non None, return that result
"""
timeout = float(timeout)
while 1:
result = fn()
if not (result is None or result is False):
return result
if timeout <= 0:
if callable(onError):
onError = onError()
raise TimeoutException(onError)
time.sleep(sleepAmt)
timeout -= sleepAmt

def expectException(fn, ExcType, comparison=None):
try:
fn()
Expand Down
4 changes: 1 addition & 3 deletions qa/rpc-tests/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,7 @@ def run_test (self):
wait_bitcoinds()
self.node_args = [['-usehd=0'], ['-usehd=0'], ['-usehd=0']]
self.nodes = start_nodes(3, self.options.tmpdir, self.node_args)
while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
# reindex will leave rpc warm up "early"; Wait for it to finish
time.sleep(0.1)
waitFor(60, lambda : [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])

'''
Expand Down
2 changes: 2 additions & 0 deletions src/.formatted-files
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ blockgeneration/miner.cpp
blockgeneration/miner.h
blockgeneration/minter.cpp
blockgeneration/minter.h
blockstorage/blockstorage.cpp
blockstorage/blockstorage.h
bloom.cpp
bloom.h
chain/block.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ BITCOIN_CORE_H = \
blockgeneration/compare.h \
blockgeneration/miner.h \
blockgeneration/minter.h \
blockstorage/blockstorage.h \
bloom.h \
chain/chain.h \
chain/chainman.h \
Expand Down Expand Up @@ -173,13 +174,15 @@ libbitcoin_server_a-clientversion.$(OBJEXT): build/build.h
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
globals.cpp \
sync.cpp \
sync_rsm.cpp \
net/addrdb.cpp \
net/addrman.cpp \
blockgeneration/blockgeneration.cpp \
blockgeneration/miner.cpp \
blockgeneration/minter.cpp \
blockstorage/blockstorage.cpp \
bloom.cpp \
chain/chain.cpp \
chain/checkpoints.cpp \
Expand Down
109 changes: 109 additions & 0 deletions src/blockstorage/blockstorage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "blockstorage.h"

#include "clientversion.h"
#include "pow.h"
#include "streams.h"
#include "util/logger.h"

fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
{
return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
}

FILE *OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
{
if (pos.IsNull())
return NULL;
fs::path path = GetBlockPosFilename(pos, prefix);
fs::create_directories(path.parent_path());
FILE *file = fopen(path.string().c_str(), fReadOnly ? "rb" : "rb+");
if (!file && !fReadOnly)
file = fopen(path.string().c_str(), "wb+");
if (!file)
{
LogPrintf("Unable to open file %s\n", path.string());
return NULL;
}
if (pos.nPos)
{
if (fseek(file, pos.nPos, SEEK_SET))
{
LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string());
fclose(file);
return NULL;
}
}
return file;
}

FILE *OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { return OpenDiskFile(pos, "blk", fReadOnly); }
FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { return OpenDiskFile(pos, "rev", fReadOnly); }
bool WriteBlockToDisk(const CBlock &block, CDiskBlockPos &pos, const CMessageHeader::MessageMagic &messageStart)
EXCLUSIVE_LOCKS_REQUIRED(cs_blockstorage)
{
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("WriteBlockToDisk: OpenBlockFile failed");

// Write index header
unsigned int nSize = GetSerializeSize(fileout, block);
fileout << FLATDATA(messageStart) << nSize;

// Write block
long fileOutPos = ftell(fileout.Get());
if (fileOutPos < 0)
return error("WriteBlockToDisk: ftell failed");
pos.nPos = (unsigned int)fileOutPos;
fileout << block;

return true;
}

bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos, const Consensus::Params &consensusParams)
EXCLUSIVE_LOCKS_REQUIRED(cs_blockstorage)
{
block.SetNull();

// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());

// Read block
try
{
filein >> block;
}
catch (const std::exception &e)
{
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
}

// Check the header
if (block.IsProofOfWork())
{
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
}
return true;
}

bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex, const Consensus::Params &consensusParams)
EXCLUSIVE_LOCKS_REQUIRED(cs_blockstorage)
{
if (!pindex)
{
return false;
}
if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams))
{
return false;
}
if (block.GetHash() != pindex->GetBlockHash())
{
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
pindex->ToString(), pindex->GetBlockPos().ToString());
}
return true;
}
28 changes: 28 additions & 0 deletions src/blockstorage/blockstorage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

#ifndef BITCOIN_BLOCK_STORAGE_H
#define BITCOIN_BLOCK_STORAGE_H

#include "chain/blockindex.h"
#include "consensus/params.h"
#include "fs.h"
#include "net/protocol.h"
#include "sync.h"

extern CCriticalSection cs_blockstorage;

/** Translation to a filesystem path */
fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix);
/** Open a block file (blk?????.dat) */
FILE *OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Open an undo file (rev?????.dat) */
FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
/** Functions for disk access for blocks */
bool WriteBlockToDisk(const CBlock &block, CDiskBlockPos &pos, const CMessageHeader::MessageMagic &messageStart)
EXCLUSIVE_LOCKS_REQUIRED(cs_blockstorage);
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos, const Consensus::Params &consensusParams)
EXCLUSIVE_LOCKS_REQUIRED(cs_blockstorage);
bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex, const Consensus::Params &consensusParams)
EXCLUSIVE_LOCKS_REQUIRED(cs_blockstorage);


#endif
10 changes: 8 additions & 2 deletions src/chain/chainman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/

#include "chainman.h"

#include "blockstorage/blockstorage.h"
#include "checkpoints.h"
#include "consensus/consensus.h"
#include "init.h"
Expand Down Expand Up @@ -422,6 +424,7 @@ bool CChainManager::LoadExternalBlockFile(const CNetworkTemplate &chainparams, F
std::pair<std::multimap<uint256, CDiskBlockPos>::iterator,
std::multimap<uint256, CDiskBlockPos>::iterator>
range = mapBlocksUnknownParent.equal_range(head);
LOCK(cs_blockstorage);
while (range.first != range.second)
{
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
Expand Down Expand Up @@ -460,14 +463,17 @@ bool CChainManager::LoadExternalBlockFile(const CNetworkTemplate &chainparams, F

void CChainManager::UnloadBlockIndex()
{
{
LOCK(cs_orphans);
mapOrphanTransactions.clear();
mapOrphanTransactionsByPrev.clear();
}
LOCK(cs_main);
setBlockIndexCandidates.clear();
chainActive.SetTip(nullptr);
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
mempool.clear();
mapOrphanTransactions.clear();
mapOrphanTransactionsByPrev.clear();
nSyncStarted = 0;
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
Expand Down
16 changes: 12 additions & 4 deletions src/chain/tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "chain/tx.h"

#include "args.h"
#include "blockstorage/blockstorage.h"
#include "chain/chain.h"
#include "consensus/consensus.h"
#include "crypto/hash.h"
Expand Down Expand Up @@ -255,8 +256,11 @@ uint64_t CTransaction::GetCoinAge(uint64_t nCoinAge, bool byValue) const
// Read block header
CBlock block;
CDiskBlockPos blockPos(txindex.nFile, txindex.nPos);
if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus()))
return false; // unable to read block of previous transaction
{
LOCK(cs_blockstorage);
if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus()))
return false; // unable to read block of previous transaction
}
if (block.GetBlockTime() + pnetMan->getActivePaymentNetwork()->getStakeMinAge() > nTime)
continue; // only count coins meeting min age requirement

Expand Down Expand Up @@ -308,8 +312,11 @@ bool CTransaction::GetCoinAge(uint64_t &nCoinAge) const
// Read block header
CBlock block;
CDiskBlockPos blockPos(txindex.nFile, txindex.nPos);
if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus()))
return false; // unable to read block of previous transaction
{
LOCK(cs_blockstorage);
if (!ReadBlockFromDisk(block, blockPos, pnetMan->getActivePaymentNetwork()->GetConsensus()))
return false; // unable to read block of previous transaction
}
if (block.GetBlockTime() + pnetMan->getActivePaymentNetwork()->getStakeMinAge() > nTime)
continue; // only count coins meeting min age requirement

Expand Down Expand Up @@ -395,6 +402,7 @@ bool GetTransaction(const uint256 &hash,
if (pindexSlow)
{
CBlock block;
LOCK(cs_blockstorage);
if (ReadBlockFromDisk(block, pindexSlow, consensusParams))
{
for (auto const &tx : block.vtx)
Expand Down
14 changes: 14 additions & 0 deletions src/globals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2019 The Eccoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"


/**
* Global state
*/

CCriticalSection cs_main;
CCriticalSection cs_orphans;
CCriticalSection cs_blockstorage;
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "amount.h"
#include "args.h"
#include "blockgeneration/blockgeneration.h"
#include "blockstorage/blockstorage.h"
#include "chain/chain.h"
#include "chain/checkpoints.h"
#include "compat/sanity.h"
Expand Down
21 changes: 14 additions & 7 deletions src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <algorithm>

#include "args.h"
#include "blockstorage/blockstorage.h"
#include "chain/chain.h"
#include "consensus/consensus.h"
#include "crypto/scrypt.h"
Expand Down Expand Up @@ -129,11 +130,14 @@ bool ComputeNextStakeModifier(const CBlockIndex *pindexPrev, const CTransaction
CBlock block;
CBlockIndex *index = pnetMan->getChainActive()->LookupBlockIndex(blockHashOfTx);

if (!ReadBlockFromDisk(block, index, pnetMan->getActivePaymentNetwork()->GetConsensus()))
{
// unable to read block of previous transaction
LogPrint("kernel", "ComputeNextStakeModifier() : read block failed");
return false;
LOCK(cs_blockstorage);
if (!ReadBlockFromDisk(block, index, pnetMan->getActivePaymentNetwork()->GetConsensus()))
{
// unable to read block of previous transaction
LogPrint("kernel", "ComputeNextStakeModifier() : read block failed");
return false;
}
}

if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier))
Expand Down Expand Up @@ -285,10 +289,13 @@ bool CheckProofOfStake(int nHeight, const CTransaction &tx, uint256 &hashProofOf
CBlock block;
CBlockIndex *index = pnetMan->getChainActive()->LookupBlockIndex(blockHashOfTx);

if (!ReadBlockFromDisk(block, index, pnetMan->getActivePaymentNetwork()->GetConsensus()))
{
LogPrint("kernel", "CheckProofOfStake() : read block failed");
return false;
LOCK(cs_blockstorage);
if (!ReadBlockFromDisk(block, index, pnetMan->getActivePaymentNetwork()->GetConsensus()))
{
LogPrint("kernel", "CheckProofOfStake() : read block failed");
return false;
}
}

CDiskTxPos txindex;
Expand Down
Loading

0 comments on commit eacea89

Please sign in to comment.