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

guard orphanmaps with cs_orphans, guard block disk access with cs_blockstorage #199

Merged
merged 4 commits into from
Jun 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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