20 #include <boost/thread.hpp> 22 static const char DB_COIN =
'C';
23 static const char DB_COINS =
'c';
24 static const char DB_BLOCK_FILES =
'f';
25 static const char DB_TXINDEX =
't';
26 static const char DB_BLOCK_INDEX =
'b';
28 static const char DB_HEIGHTINDEX =
'h';
31 static const char DB_BEST_BLOCK =
'B';
32 static const char DB_HEAD_BLOCKS =
'H';
33 static const char DB_FLAG =
'F';
34 static const char DB_REINDEX_FLAG =
'R';
35 static const char DB_LAST_BLOCK =
'l';
42 CoinEntry(
const COutPoint* ptr) : outpoint(const_cast<
COutPoint*>(ptr)), key(DB_COIN) {}
44 template<
typename Stream>
51 template<
typename Stream>
66 return db.
Read(CoinEntry(&outpoint), coin);
70 return db.
Exists(CoinEntry(&outpoint));
75 if (!
db.
Read(DB_BEST_BLOCK, hashBestChain))
81 std::vector<uint256> vhashHeadBlocks;
82 if (!
db.
Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
83 return std::vector<uint256>();
85 return vhashHeadBlocks;
92 size_t batch_size = (size_t)
gArgs.
GetArg(
"-dbbatchsize", nDefaultDbBatchSize);
93 int crash_simulate =
gArgs.
GetArg(
"-dbcrashratio", 0);
97 if (old_tip.IsNull()) {
100 if (old_heads.size() == 2) {
101 assert(old_heads[0] == hashBlock);
102 old_tip = old_heads[1];
110 batch.
Erase(DB_BEST_BLOCK);
111 batch.
Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip});
113 for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
115 CoinEntry entry(&it->first);
116 if (it->second.coin.IsSpent())
119 batch.
Write(entry, it->second.coin);
123 CCoinsMap::iterator itOld = it++;
124 mapCoins.erase(itOld);
129 if (crash_simulate) {
131 if (rng.
randrange(crash_simulate) == 0) {
132 LogPrintf(
"Simulating a crash. Goodbye.\n");
140 batch.
Erase(DB_HEAD_BLOCKS);
141 batch.
Write(DB_BEST_BLOCK, hashBlock);
145 LogPrint(
BCLog::COINDB,
"Committed %u changed transaction outputs (out of %u) to coin database...\n", (
unsigned int)changed, (
unsigned int)count);
158 return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
163 return Write(DB_REINDEX_FLAG,
'1');
165 return Erase(DB_REINDEX_FLAG);
169 fReindexing =
Exists(DB_REINDEX_FLAG);
174 return Read(DB_LAST_BLOCK, nFile);
186 CoinEntry entry(&i->
keyTmp.second);
188 i->
keyTmp.first = entry.key;
198 if (keyTmp.first == DB_COIN) {
207 return pcursor->GetValue(coin);
212 return pcursor->GetValueSize();
217 return keyTmp.first == DB_COIN;
223 CoinEntry entry(&keyTmp.second);
224 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
227 keyTmp.first = entry.key;
231 bool CBlockTreeDB::WriteBatchSync(
const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo,
int nLastFile,
const std::vector<const CBlockIndex*>& blockinfo) {
233 for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
234 batch.
Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
236 batch.
Write(DB_LAST_BLOCK, nLastFile);
237 for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
244 return Read(std::make_pair(DB_TXINDEX, txid), pos);
249 for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
250 batch.
Write(std::make_pair(DB_TXINDEX, it->first), it->second);
255 return Write(std::make_pair(DB_FLAG, name), fValue ?
'1' :
'0');
260 if (!
Read(std::make_pair(DB_FLAG, name), ch))
269 batch.
Write(std::make_pair(DB_HEIGHTINDEX, heightIndex), hash);
274 std::vector<std::vector<uint256>> &blocksOfHashes,
275 std::set<dev::h160>
const &addresses) {
277 if ((high < low && high > -1) || (high == 0 && low == 0) || (high < -1 || low < 0)) {
281 std::unique_ptr<CDBIterator> pcursor(
NewIterator());
287 for (
size_t count = 0; pcursor->Valid(); pcursor->Next()) {
289 std::pair<char, CHeightTxIndexKey> key;
290 if (!pcursor->GetKey(key) || key.first != DB_HEIGHTINDEX) {
294 int nextHeight = key.second.height;
296 if (high > -1 && nextHeight > high) {
302 if (conf < minconf) {
307 curheight = nextHeight;
309 auto address = key.second.address;
310 if (!addresses.empty() && addresses.find(
address) == addresses.end()) {
314 std::vector<uint256> hashesTx;
316 if (!pcursor->GetValue(hashesTx)) {
320 count += hashesTx.size();
322 blocksOfHashes.push_back(hashesTx);
330 boost::scoped_ptr<CDBIterator> pcursor(
NewIterator());
335 while (pcursor->Valid()) {
336 boost::this_thread::interruption_point();
337 std::pair<char, CHeightTxIndexKey> key;
338 if (pcursor->GetKey(key) && key.first == DB_HEIGHTINDEX && key.second.height == height) {
351 boost::scoped_ptr<CDBIterator> pcursor(
NewIterator());
354 pcursor->Seek(DB_HEIGHTINDEX);
356 while (pcursor->Valid()) {
357 boost::this_thread::interruption_point();
358 std::pair<char, CHeightTxIndexKey> key;
359 if (pcursor->GetKey(key) && key.first == DB_HEIGHTINDEX) {
372 std::unique_ptr<CDBIterator> pcursor(
NewIterator());
374 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX,
uint256()));
377 while (pcursor->Valid()) {
378 boost::this_thread::interruption_point();
379 std::pair<char, uint256> key;
380 if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
382 if (pcursor->GetValue(diskindex)) {
398 pindexNew->
nTx = diskindex.
nTx;
403 bool postfork = (uint32_t)pindexNew->
nHeight >= (uint32_t)consensusParams.
FABHeight;
405 return error(
"%s: CheckProofOfWork failed: %s", __func__, pindexNew->
ToString());
409 return error(
"%s: failed to read value", __func__);
429 std::vector<CTxOut> vout;
435 CCoins() : fCoinBase(
false), vout(0), nHeight(0) { }
437 template<
typename Stream>
439 unsigned int nCode = 0;
445 fCoinBase = nCode & 1;
446 std::vector<bool> vAvail(2,
false);
447 vAvail[0] = (nCode & 2) != 0;
448 vAvail[1] = (nCode & 4) != 0;
449 unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
451 while (nMaskCode > 0) {
452 unsigned char chAvail = 0;
454 for (
unsigned int p = 0; p < 8; p++) {
455 bool f = (chAvail & (1 << p)) != 0;
462 vout.assign(vAvail.size(),
CTxOut());
463 for (
unsigned int i = 0; i < vAvail.size(); i++) {
479 std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
480 pcursor->Seek(std::make_pair(DB_COINS,
uint256()));
481 if (!pcursor->Valid()) {
486 LogPrintf(
"Upgrading utxo-set database...\n");
488 size_t batch_size = 1 << 24;
492 std::pair<unsigned char, uint256> key;
493 std::pair<unsigned char, uint256> prev_key = {DB_COINS,
uint256()};
494 while (pcursor->Valid()) {
495 boost::this_thread::interruption_point();
499 if (pcursor->GetKey(key) && key.first == DB_COINS) {
500 if (count++ % 256 == 0) {
501 uint32_t high = 0x100 * *key.second.begin() + *(key.second.begin() + 1);
502 int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5);
503 uiInterface.
ShowProgress(
_(
"Upgrading UTXO database") +
"\n"+
_(
"(press q to shutdown and continue later)") +
"\n", percentageDone);
504 if (reportDone < percentageDone/10) {
507 reportDone = percentageDone/10;
511 if (!pcursor->GetValue(old_coins)) {
512 return error(
"%s: cannot parse CCoins record", __func__);
515 for (
size_t i = 0; i < old_coins.vout.size(); ++i) {
516 if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
517 Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
519 CoinEntry entry(&outpoint);
520 batch.
Write(entry, newcoin);
525 db.WriteBatch(batch);
527 db.CompactRange(prev_key, key);
535 db.WriteBatch(batch);
536 db.CompactRange({DB_COINS,
uint256()}, key);
bool GetValue(Coin &coin) const override
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
bool error(const char *fmt, const Args &...args)
#define function(a, b, c, d, k, s)
bool Upgrade()
Attempt to update from an older database format. Returns whether an error occurred.
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
bool EraseHeightIndex(const unsigned int &height)
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Batch of changes queued to be written to a CDBWrapper.
bool ReadReindexing(bool &fReindex)
bool ReadLastBlockFile(int &nFile)
wrapper for CTxOut that provides a more compact serialization
size_t SizeEstimate() const
std::unique_ptr< CDBIterator > pcursor
uint64_t randrange(uint64_t range)
Generate a random integer in the range [0..range).
std::string ToString() const
assert(len-trim+(2 *lenIndices)<=WIDTH)
int nFile
Which # file this block is stored in (blk?????.dat)
bool GetKey(COutPoint &key) const override
uint32_t FABHeight
Block height at which Fabcoin Equihash hard fork becomes active.
CDBIterator * NewIterator()
void Serialize(Stream &s, char a)
int Height() const
Return the maximal height in the chain.
bool CheckProofOfWork(uint256 hash, unsigned int nBits, bool postfork, const Consensus::Params ¶ms)
Check whether a block hash satisfies the proof-of-work requirement specified by nBits.
unsigned int nStatus
Verification status of this block. See enum BlockStatus.
bool Erase(const K &key, bool fSync=false)
unsigned int nDataPos
Byte offset within blk?????.dat where this block's data is stored.
uint256 GetBlockHash() const
bool WriteBatchSync(const std::vector< std::pair< int, const CBlockFileInfo * > > &fileInfo, int nLastFile, const std::vector< const CBlockIndex * > &blockinfo)
size_t EstimateSize(const K &key_begin, const K &key_end) const
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedOutpointHasher > CCoinsMap
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
void Write(const K &key, const V &value)
An output of a transaction.
Used to marshal pointers into hashes for db storage.
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Parameters that influence chain consensus.
An outpoint - a combination of a transaction hash and an index n into its vout.
std::pair< char, COutPoint > keyTmp
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
bool ReadFlag(const std::string &name, bool &fValue)
CBlockTreeDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo)
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos)
CCoinsViewDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
unsigned int nUndoPos
Byte offset within rev?????.dat where this block's undo data is stored.
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
#define LogPrint(category,...)
bool Write(const K &key, const V &value, bool fSync=false)
The block chain is a tree shaped structure starting with the genesis block at the root...
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
void * memcpy(void *a, const void *b, size_t c)
boost::signals2::signal< void(std::function< void(void)> action)> SetProgressBreakAction
Set progress break action (possible "cancel button" triggers that action)
bool WriteTxIndex(const std::vector< std::pair< uint256, CDiskTxPos > > &list)
void Unserialize(Stream &s, char &a)
bool WriteReindexing(bool fReindex)
bool LoadBlockIndexGuts(const Consensus::Params &consensusParams, std::function< CBlockIndex *(const uint256 &)> insertBlockIndex)
bool WriteFlag(const std::string &name, bool fValue)
bool Exists(const K &key) const
bool Read(const K &key, V &value) const
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
const fs::path & GetDataDir(bool fNetSpecific)
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
bool WriteBatch(CDBBatch &batch, bool fSync=false)
struct evm_uint160be address(struct evm_env *env)
bool Valid() const override
CClientUIInterface uiInterface
int nHeight
height of the entry in the chain. The genesis block has height 0
bool WriteHeightIndex(const CHeightTxIndexKey &heightIndex, const std::vector< uint256 > &hash)
uint32_t ch(uint32_t x, uint32_t y, uint32_t z)
unsigned int GetValueSize() const override
T & REF(const T &val)
Used to bypass the rule against non-const reference to temporary where it makes sense with wrappers s...
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
int ReadHeightIndex(int low, int high, int minconf, std::vector< std::vector< uint256 >> &blocksOfHashes, std::set< dev::h160 > const &addresses)
Iterates through blocks by height, starting from low.
unsigned int nTx
Number of transactions in this block.
std::vector< unsigned char > nSolution
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
uint256 GetBlockHash() const
Cursor for iterating over CoinsView state.