Skip to content
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
54 changes: 54 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,60 @@

#include <vector>

class CBlockFileInfo
{
public:
unsigned int nBlocks; //!< number of blocks stored in file
unsigned int nSize; //!< number of used bytes of block file
unsigned int nUndoSize; //!< number of used bytes in the undo file
unsigned int nHeightFirst; //!< lowest height of block in file
unsigned int nHeightLast; //!< highest height of block in file
uint64_t nTimeFirst; //!< earliest time of block in file
uint64_t nTimeLast; //!< latest time of block in file

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(VARINT(nBlocks));
READWRITE(VARINT(nSize));
READWRITE(VARINT(nUndoSize));
READWRITE(VARINT(nHeightFirst));
READWRITE(VARINT(nHeightLast));
READWRITE(VARINT(nTimeFirst));
READWRITE(VARINT(nTimeLast));
}

void SetNull() {
nBlocks = 0;
nSize = 0;
nUndoSize = 0;
nHeightFirst = 0;
nHeightLast = 0;
nTimeFirst = 0;
nTimeLast = 0;
}

CBlockFileInfo() {
SetNull();
}

std::string ToString() const;

/** update statistics (does not update nSize) */
void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
if (nBlocks==0 || nHeightFirst > nHeightIn)
nHeightFirst = nHeightIn;
if (nBlocks==0 || nTimeFirst > nTimeIn)
nTimeFirst = nTimeIn;
nBlocks++;
if (nHeightIn > nHeightLast)
nHeightLast = nHeightIn;
if (nTimeIn > nTimeLast)
nTimeLast = nTimeIn;
}
};

struct CDiskBlockPos
{
int nFile;
Expand Down
20 changes: 15 additions & 5 deletions src/coins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return fal
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }


CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
Expand All @@ -54,9 +54,9 @@ bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveC
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }

CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}

CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }

Expand Down Expand Up @@ -117,11 +117,17 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
return CCoinsModifier(*this, ret.first, cachedCoinUsage);
}

CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) {
// ModifyNewCoins has to know whether the new outputs its creating are for a
// coinbase or not. If they are for a coinbase, it can not mark them as fresh.
// This is to ensure that the historical duplicate coinbases before BIP30 was
// in effect will still be properly overwritten when spent.
CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) {
assert(!hasModifier);
std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
ret.first->second.coins.Clear();
ret.first->second.flags = CCoinsCacheEntry::FRESH;
if (!coinbase) {
ret.first->second.flags = CCoinsCacheEntry::FRESH;
}
ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
return CCoinsModifier(*this, ret.first, 0);
}
Expand Down Expand Up @@ -294,3 +300,7 @@ CCoinsModifier::~CCoinsModifier()
cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage();
}
}

CCoinsViewCursor::~CCoinsViewCursor()
{
}
49 changes: 29 additions & 20 deletions src/coins.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "compressor.h"
#include "core_memusage.h"
#include "hash.h"
#include "memusage.h"
#include "serialize.h"
#include "uint256.h"
Expand Down Expand Up @@ -264,21 +265,22 @@ class CCoins
}
};

class CCoinsKeyHasher
class SaltedTxidHasher
{
private:
uint256 salt;
/** Salt */
const uint64_t k0, k1;

public:
CCoinsKeyHasher();
SaltedTxidHasher();

/**
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
* unordered_map will behave unpredictably if the custom hasher returns a
* uint64_t, resulting in failures when syncing the chain (#4634).
*/
size_t operator()(const uint256& key) const {
return key.GetHash(salt);
size_t operator()(const uint256& txid) const {
return SipHashUint256(k0, k1, txid);
}
};

Expand All @@ -295,21 +297,28 @@ struct CCoinsCacheEntry
CCoinsCacheEntry() : coins(), flags(0) {}
};

typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
typedef boost::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;

struct CCoinsStats
/** Cursor for iterating over CoinsView state */
class CCoinsViewCursor
{
int nHeight;
uint256 hashBlock;
uint64_t nTransactions;
uint64_t nTransactionOutputs;
uint64_t nSerializedSize;
uint256 hashSerialized;
CAmount nTotalAmount;
public:
CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}
virtual ~CCoinsViewCursor();

CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {}
};
virtual bool GetKey(uint256 &key) const = 0;
virtual bool GetValue(CCoins &coins) const = 0;
/* Don't care about GetKeySize here */
virtual unsigned int GetValueSize() const = 0;

virtual bool Valid() const = 0;
virtual void Next() = 0;

//! Get best block at the time this cursor was created
const uint256 &GetBestBlock() const { return hashBlock; }
private:
uint256 hashBlock;
};

/** Abstract view on the open txout dataset. */
class CCoinsView
Expand All @@ -329,8 +338,8 @@ class CCoinsView
//! The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);

//! Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats) const;
//! Get a cursor to iterate over the whole state
virtual CCoinsViewCursor *Cursor() const;

//! As we use CCoinsViews polymorphically, have a virtual destructor
virtual ~CCoinsView() {}
Expand All @@ -350,7 +359,7 @@ class CCoinsViewBacked : public CCoinsView
uint256 GetBestBlock() const;
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
bool GetStats(CCoinsStats &stats) const;
CCoinsViewCursor *Cursor() const;
};


Expand Down Expand Up @@ -435,7 +444,7 @@ class CCoinsViewCache : public CCoinsViewBacked
* would not properly overwrite the first coinbase of the pair. Simultaneous modifications
* are not allowed.
*/
CCoinsModifier ModifyNewCoins(const uint256 &txid);
CCoinsModifier ModifyNewCoins(const uint256 &txid, bool coinbase);

/**
* Push the modifications applied to this cache to its base.
Expand Down
10 changes: 8 additions & 2 deletions src/compressor.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,14 @@ class CScriptCompressor
return;
}
nSize -= nSpecialScripts;
script.resize(nSize);
s >> REF(CFlatData(script));
if (nSize > MAX_SCRIPT_SIZE) {
// Overly long script, replace with a short invalid one
script << OP_RETURN;
s.ignore(nSize);
} else {
script.resize(nSize);
s >> REF(CFlatData(script));
}
}
};

Expand Down
55 changes: 27 additions & 28 deletions src/dbwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,6 @@
#include <memenv.h>
#include <stdint.h>

void HandleError(const leveldb::Status& status) throw(dbwrapper_error)
{
if (status.ok())
return;
LogPrintf("%s\n", status.ToString());
if (status.IsCorruption())
throw dbwrapper_error("Database corrupted");
if (status.IsIOError())
throw dbwrapper_error("Database I/O error");
if (status.IsNotFound())
throw dbwrapper_error("Database entry missing");
throw dbwrapper_error("Unknown database error");
}

static leveldb::Options GetOptions(size_t nCacheSize)
{
leveldb::Options options;
Expand Down Expand Up @@ -61,13 +47,13 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b
if (fWipe) {
LogPrintf("Wiping LevelDB in %s\n", path.string());
leveldb::Status result = leveldb::DestroyDB(path.string(), options);
HandleError(result);
dbwrapper_private::HandleError(result);
}
TryCreateDirectory(path);
LogPrintf("Opening LevelDB in %s\n", path.string());
}
leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
HandleError(status);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");

// The base-case obfuscation key, which is a noop.
Expand All @@ -84,10 +70,10 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b
Write(OBFUSCATE_KEY_KEY, new_key);
obfuscate_key = new_key;

LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex());
LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
}

LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex());
LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
}

CDBWrapper::~CDBWrapper()
Expand All @@ -102,10 +88,10 @@ CDBWrapper::~CDBWrapper()
options.env = NULL;
}

bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error)
bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
{
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
HandleError(status);
dbwrapper_private::HandleError(status);
return true;
}

Expand Down Expand Up @@ -136,17 +122,30 @@ bool CDBWrapper::IsEmpty()
return !(it->Valid());
}

const std::vector<unsigned char>& CDBWrapper::GetObfuscateKey() const
CDBIterator::~CDBIterator() { delete piter; }
bool CDBIterator::Valid() { return piter->Valid(); }
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
void CDBIterator::Next() { piter->Next(); }

namespace dbwrapper_private {

void HandleError(const leveldb::Status& status)
{
return obfuscate_key;
if (status.ok())
return;
LogPrintf("%s\n", status.ToString());
if (status.IsCorruption())
throw dbwrapper_error("Database corrupted");
if (status.IsIOError())
throw dbwrapper_error("Database I/O error");
if (status.IsNotFound())
throw dbwrapper_error("Database entry missing");
throw dbwrapper_error("Unknown database error");
}

std::string CDBWrapper::GetObfuscateKeyHex() const
const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
{
return HexStr(obfuscate_key);
return w.obfuscate_key;
}

CDBIterator::~CDBIterator() { delete piter; }
bool CDBIterator::Valid() { return piter->Valid(); }
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
void CDBIterator::Next() { piter->Next(); }
};
Loading