Skip to content

Commit 0fdd11c

Browse files
authored
Merge pull request #1691 from codablock/backport_bitcoin_perutxo_0.13
First batch of per-utxo backports (up until 0.13)
2 parents 4ecbedb + e3b7ed4 commit 0fdd11c

24 files changed

+865
-604
lines changed

src/chain.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,60 @@
1414

1515
#include <vector>
1616

17+
class CBlockFileInfo
18+
{
19+
public:
20+
unsigned int nBlocks; //!< number of blocks stored in file
21+
unsigned int nSize; //!< number of used bytes of block file
22+
unsigned int nUndoSize; //!< number of used bytes in the undo file
23+
unsigned int nHeightFirst; //!< lowest height of block in file
24+
unsigned int nHeightLast; //!< highest height of block in file
25+
uint64_t nTimeFirst; //!< earliest time of block in file
26+
uint64_t nTimeLast; //!< latest time of block in file
27+
28+
ADD_SERIALIZE_METHODS;
29+
30+
template <typename Stream, typename Operation>
31+
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
32+
READWRITE(VARINT(nBlocks));
33+
READWRITE(VARINT(nSize));
34+
READWRITE(VARINT(nUndoSize));
35+
READWRITE(VARINT(nHeightFirst));
36+
READWRITE(VARINT(nHeightLast));
37+
READWRITE(VARINT(nTimeFirst));
38+
READWRITE(VARINT(nTimeLast));
39+
}
40+
41+
void SetNull() {
42+
nBlocks = 0;
43+
nSize = 0;
44+
nUndoSize = 0;
45+
nHeightFirst = 0;
46+
nHeightLast = 0;
47+
nTimeFirst = 0;
48+
nTimeLast = 0;
49+
}
50+
51+
CBlockFileInfo() {
52+
SetNull();
53+
}
54+
55+
std::string ToString() const;
56+
57+
/** update statistics (does not update nSize) */
58+
void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
59+
if (nBlocks==0 || nHeightFirst > nHeightIn)
60+
nHeightFirst = nHeightIn;
61+
if (nBlocks==0 || nTimeFirst > nTimeIn)
62+
nTimeFirst = nTimeIn;
63+
nBlocks++;
64+
if (nHeightIn > nHeightLast)
65+
nHeightLast = nHeightIn;
66+
if (nTimeIn > nTimeLast)
67+
nTimeLast = nTimeIn;
68+
}
69+
};
70+
1771
struct CDiskBlockPos
1872
{
1973
int nFile;

src/coins.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return fal
4545
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
4646
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
4747
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
48-
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
48+
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
4949

5050

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

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

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

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

120-
CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid) {
120+
// ModifyNewCoins has to know whether the new outputs its creating are for a
121+
// coinbase or not. If they are for a coinbase, it can not mark them as fresh.
122+
// This is to ensure that the historical duplicate coinbases before BIP30 was
123+
// in effect will still be properly overwritten when spent.
124+
CCoinsModifier CCoinsViewCache::ModifyNewCoins(const uint256 &txid, bool coinbase) {
121125
assert(!hasModifier);
122126
std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
123127
ret.first->second.coins.Clear();
124-
ret.first->second.flags = CCoinsCacheEntry::FRESH;
128+
if (!coinbase) {
129+
ret.first->second.flags = CCoinsCacheEntry::FRESH;
130+
}
125131
ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
126132
return CCoinsModifier(*this, ret.first, 0);
127133
}
@@ -294,3 +300,7 @@ CCoinsModifier::~CCoinsModifier()
294300
cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage();
295301
}
296302
}
303+
304+
CCoinsViewCursor::~CCoinsViewCursor()
305+
{
306+
}

src/coins.h

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "compressor.h"
1010
#include "core_memusage.h"
11+
#include "hash.h"
1112
#include "memusage.h"
1213
#include "serialize.h"
1314
#include "uint256.h"
@@ -264,21 +265,22 @@ class CCoins
264265
}
265266
};
266267

267-
class CCoinsKeyHasher
268+
class SaltedTxidHasher
268269
{
269270
private:
270-
uint256 salt;
271+
/** Salt */
272+
const uint64_t k0, k1;
271273

272274
public:
273-
CCoinsKeyHasher();
275+
SaltedTxidHasher();
274276

275277
/**
276278
* This *must* return size_t. With Boost 1.46 on 32-bit systems the
277279
* unordered_map will behave unpredictably if the custom hasher returns a
278280
* uint64_t, resulting in failures when syncing the chain (#4634).
279281
*/
280-
size_t operator()(const uint256& key) const {
281-
return key.GetHash(salt);
282+
size_t operator()(const uint256& txid) const {
283+
return SipHashUint256(k0, k1, txid);
282284
}
283285
};
284286

@@ -295,21 +297,28 @@ struct CCoinsCacheEntry
295297
CCoinsCacheEntry() : coins(), flags(0) {}
296298
};
297299

298-
typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
300+
typedef boost::unordered_map<uint256, CCoinsCacheEntry, SaltedTxidHasher> CCoinsMap;
299301

300-
struct CCoinsStats
302+
/** Cursor for iterating over CoinsView state */
303+
class CCoinsViewCursor
301304
{
302-
int nHeight;
303-
uint256 hashBlock;
304-
uint64_t nTransactions;
305-
uint64_t nTransactionOutputs;
306-
uint64_t nSerializedSize;
307-
uint256 hashSerialized;
308-
CAmount nTotalAmount;
305+
public:
306+
CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}
307+
virtual ~CCoinsViewCursor();
309308

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

314+
virtual bool Valid() const = 0;
315+
virtual void Next() = 0;
316+
317+
//! Get best block at the time this cursor was created
318+
const uint256 &GetBestBlock() const { return hashBlock; }
319+
private:
320+
uint256 hashBlock;
321+
};
313322

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

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

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

356365

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

440449
/**
441450
* Push the modifications applied to this cache to its base.

src/compressor.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,14 @@ class CScriptCompressor
8686
return;
8787
}
8888
nSize -= nSpecialScripts;
89-
script.resize(nSize);
90-
s >> REF(CFlatData(script));
89+
if (nSize > MAX_SCRIPT_SIZE) {
90+
// Overly long script, replace with a short invalid one
91+
script << OP_RETURN;
92+
s.ignore(nSize);
93+
} else {
94+
script.resize(nSize);
95+
s >> REF(CFlatData(script));
96+
}
9197
}
9298
};
9399

src/dbwrapper.cpp

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,6 @@
1515
#include <memenv.h>
1616
#include <stdint.h>
1717

18-
void HandleError(const leveldb::Status& status) throw(dbwrapper_error)
19-
{
20-
if (status.ok())
21-
return;
22-
LogPrintf("%s\n", status.ToString());
23-
if (status.IsCorruption())
24-
throw dbwrapper_error("Database corrupted");
25-
if (status.IsIOError())
26-
throw dbwrapper_error("Database I/O error");
27-
if (status.IsNotFound())
28-
throw dbwrapper_error("Database entry missing");
29-
throw dbwrapper_error("Unknown database error");
30-
}
31-
3218
static leveldb::Options GetOptions(size_t nCacheSize)
3319
{
3420
leveldb::Options options;
@@ -61,13 +47,13 @@ CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, b
6147
if (fWipe) {
6248
LogPrintf("Wiping LevelDB in %s\n", path.string());
6349
leveldb::Status result = leveldb::DestroyDB(path.string(), options);
64-
HandleError(result);
50+
dbwrapper_private::HandleError(result);
6551
}
6652
TryCreateDirectory(path);
6753
LogPrintf("Opening LevelDB in %s\n", path.string());
6854
}
6955
leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
70-
HandleError(status);
56+
dbwrapper_private::HandleError(status);
7157
LogPrintf("Opened LevelDB successfully\n");
7258

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

87-
LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), GetObfuscateKeyHex());
73+
LogPrintf("Wrote new obfuscate key for %s: %s\n", path.string(), HexStr(obfuscate_key));
8874
}
8975

90-
LogPrintf("Using obfuscation key for %s: %s\n", path.string(), GetObfuscateKeyHex());
76+
LogPrintf("Using obfuscation key for %s: %s\n", path.string(), HexStr(obfuscate_key));
9177
}
9278

9379
CDBWrapper::~CDBWrapper()
@@ -102,10 +88,10 @@ CDBWrapper::~CDBWrapper()
10288
options.env = NULL;
10389
}
10490

105-
bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) throw(dbwrapper_error)
91+
bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
10692
{
10793
leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch);
108-
HandleError(status);
94+
dbwrapper_private::HandleError(status);
10995
return true;
11096
}
11197

@@ -136,17 +122,30 @@ bool CDBWrapper::IsEmpty()
136122
return !(it->Valid());
137123
}
138124

139-
const std::vector<unsigned char>& CDBWrapper::GetObfuscateKey() const
125+
CDBIterator::~CDBIterator() { delete piter; }
126+
bool CDBIterator::Valid() { return piter->Valid(); }
127+
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
128+
void CDBIterator::Next() { piter->Next(); }
129+
130+
namespace dbwrapper_private {
131+
132+
void HandleError(const leveldb::Status& status)
140133
{
141-
return obfuscate_key;
134+
if (status.ok())
135+
return;
136+
LogPrintf("%s\n", status.ToString());
137+
if (status.IsCorruption())
138+
throw dbwrapper_error("Database corrupted");
139+
if (status.IsIOError())
140+
throw dbwrapper_error("Database I/O error");
141+
if (status.IsNotFound())
142+
throw dbwrapper_error("Database entry missing");
143+
throw dbwrapper_error("Unknown database error");
142144
}
143145

144-
std::string CDBWrapper::GetObfuscateKeyHex() const
146+
const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
145147
{
146-
return HexStr(obfuscate_key);
148+
return w.obfuscate_key;
147149
}
148150

149-
CDBIterator::~CDBIterator() { delete piter; }
150-
bool CDBIterator::Valid() { return piter->Valid(); }
151-
void CDBIterator::SeekToFirst() { piter->SeekToFirst(); }
152-
void CDBIterator::Next() { piter->Next(); }
151+
};

0 commit comments

Comments
 (0)