18 #include <boost/thread.hpp>
20 static const char DB_COIN =
'C';
21 static const char DB_COINS =
'c';
22 static const char DB_BLOCK_FILES =
'f';
23 static const char DB_TXINDEX =
't';
24 static const char DB_BLOCK_INDEX =
'b';
26 static const char DB_BEST_BLOCK =
'B';
27 static const char DB_HEAD_BLOCKS =
'H';
28 static const char DB_FLAG =
'F';
29 static const char DB_REINDEX_FLAG =
'R';
30 static const char DB_LAST_BLOCK =
'l';
39 explicit CoinEntry(
const COutPoint* ptr) : outpoint(const_cast<
COutPoint*>(ptr)), key(DB_COIN) {}
53 return db.
Read(CoinEntry(&outpoint), coin);
58 return db.
Exists(CoinEntry(&outpoint));
64 if (!
db.
Read(DB_BEST_BLOCK, hashBestChain))
70 std::vector<uint256> vhashHeadBlocks;
71 if (!
db.
Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
72 return std::vector<uint256>();
74 return vhashHeadBlocks;
79 const uint256& hashSaplingAnchor,
86 size_t batch_size = (size_t)
gArgs.
GetArg(
"-dbbatchsize", nDefaultDbBatchSize);
87 int crash_simulate =
gArgs.
GetArg(
"-dbcrashratio", 0);
88 assert(!hashBlock.
IsNull());
94 if (old_heads.size() == 2) {
95 assert(old_heads[0] == hashBlock);
96 old_tip = old_heads[1];
104 batch.
Erase(DB_BEST_BLOCK);
105 batch.
Write(DB_HEAD_BLOCKS,
Vector(hashBlock, old_tip));
107 for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
109 CoinEntry entry(&it->first);
110 if (it->second.coin.IsSpent())
113 batch.
Write(entry, it->second.coin);
117 CCoinsMap::iterator itOld = it++;
118 mapCoins.erase(itOld);
123 if (crash_simulate) {
125 if (rng.
randrange(crash_simulate) == 0) {
126 LogPrintf(
"Simulating a crash. Goodbye.\n");
134 BatchWriteSapling(hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers, batch);
137 batch.
Erase(DB_HEAD_BLOCKS);
138 batch.
Write(DB_BEST_BLOCK, hashBlock);
142 LogPrint(
BCLog::COINDB,
"Committed %u changed transaction outputs (out of %u) to coin database...\n", (
unsigned int)changed, (
unsigned int)count);
157 return Write(std::make_pair(DB_BLOCK_INDEX, blockindex.
GetBlockHash()), blockindex);
162 return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
168 return Write(DB_REINDEX_FLAG,
'1');
170 return Erase(DB_REINDEX_FLAG);
175 fReindexing =
Exists(DB_REINDEX_FLAG);
181 return Read(DB_LAST_BLOCK, nFile);
194 CoinEntry entry(&i->
keyTmp.second);
196 i->
keyTmp.first = entry.key;
206 if (
keyTmp.first == DB_COIN) {
215 return pcursor->GetValue(coin);
220 return pcursor->GetValueSize();
225 return keyTmp.first == DB_COIN;
231 CoinEntry entry(&
keyTmp.second);
239 bool CBlockTreeDB::WriteBatchSync(
const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo,
int nLastFile,
const std::vector<const CBlockIndex*>& blockinfo) {
241 for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
242 batch.
Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
244 batch.
Write(DB_LAST_BLOCK, nLastFile);
245 for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
253 return Read(std::make_pair(DB_TXINDEX, txid), pos);
259 for (std::vector<std::pair<uint256, CDiskTxPos> >::const_iterator it = vect.begin(); it != vect.end(); it++)
260 batch.
Write(std::make_pair(DB_TXINDEX, it->first), it->second);
266 return Write(std::make_pair(DB_FLAG,
name), fValue ?
'1' :
'0');
272 if (!
Read(std::make_pair(DB_FLAG,
name), ch))
280 return Write(std::make_pair(
'I',
name), nValue);
285 return Read(std::make_pair(
'I',
name), nValue);
290 std::unique_ptr<CDBIterator> pcursor(
NewIterator());
292 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX,
UINT256_ZERO));
295 while (pcursor->Valid()) {
296 boost::this_thread::interruption_point();
297 std::pair<char, uint256> key;
298 if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
300 if (pcursor->GetValue(diskindex)) {
314 pindexNew->
nTx = diskindex.
nTx;
329 return error(
"%s : CheckProofOfWork failed: %s", __func__, pindexNew->
ToString());
334 return error(
"%s : failed to read value", __func__);
352 for (std::vector<std::pair<CBigNum, uint256> >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) {
357 batch.
Write(std::make_pair(
's', hash), it->second);
371 return Read(std::make_pair(
's', hash), txHash);
380 return Erase(std::make_pair(
's', hash));
384 static const char LZC_ACCUMCS =
'A';
389 return Write(std::make_pair(LZC_ACCUMCS, std::make_pair(nChecksum, denom)), nHeight);
394 return Read(std::make_pair(LZC_ACCUMCS, std::make_pair(nChecksum, denom)), nHeightRet);
399 return Erase(std::make_pair(LZC_ACCUMCS, std::make_pair(nChecksum, denom)));
404 std::unique_ptr<CDBIterator> pcursor(
NewIterator());
406 while (pcursor->Valid()) {
407 boost::this_thread::interruption_point();
408 std::pair<char, std::pair<uint32_t, libzerocoin::CoinDenomination>> key;
409 if (pcursor->GetKey(key) && key.first == LZC_ACCUMCS) {
411 if (pcursor->GetValue(height)) {
412 mapCheckpoints[key.second] = height;
415 return error(
"%s : failed to read value", __func__);
422 LogPrintf(
"%s: Total acc checksum records: %d\n", __func__, mapCheckpoints.size());
428 std::unique_ptr<CDBIterator> pcursor(
NewIterator());
430 std::set<std::pair<char, std::pair<uint32_t, libzerocoin::CoinDenomination>>> setDelete;
431 while (pcursor->Valid()) {
432 boost::this_thread::interruption_point();
433 std::pair<char, std::pair<uint32_t, libzerocoin::CoinDenomination>> key;
434 if (pcursor->GetKey(key) && key.first == LZC_ACCUMCS) {
435 setDelete.insert(key);
443 for (
const auto& k : setDelete) {
445 LogPrintf(
"%s: failed to delete acc checksum %d-%d\n", __func__, k.second.first, k.second.second);
451 LogPrintf(
"%s: %d entries to delete. %d entries deleted\n", __func__, setDelete.size(), deleted);
465 std::vector<CTxOut> vout;
470 template <
typename Stream>
473 unsigned int nCode = 0;
475 unsigned int nVersionDummy;
479 fCoinBase = nCode & 1;
480 fCoinStake = (nCode & 2) != 0;
481 std::vector<bool> vAvail(2,
false);
482 vAvail[0] = (nCode & 4) != 0;
483 vAvail[1] = (nCode & 8) != 0;
484 unsigned int nMaskCode = (nCode / 16) + ((nCode & 12) != 0 ? 0 : 1);
486 while (nMaskCode > 0) {
487 unsigned char chAvail = 0;
489 for (
unsigned int p = 0; p < 8; p++) {
490 bool f = (chAvail & (1 << p)) != 0;
497 vout.assign(vAvail.size(),
CTxOut());
498 for (
unsigned int i = 0; i < vAvail.size(); i++) {
516 pcursor->Seek(std::make_pair(DB_COINS,
uint256()));
517 if (!pcursor->Valid()) {
521 LogPrintf(
"Upgrading database...\n");
522 size_t batch_size = 1 << 24;
524 while (pcursor->Valid()) {
525 boost::this_thread::interruption_point();
526 std::pair<unsigned char, uint256> key;
527 if (pcursor->GetKey(key) && key.first == DB_COINS) {
529 if (!pcursor->GetValue(old_coins)) {
530 return error(
"%s: cannot parse CCoins record", __func__);
533 for (
size_t i = 0; i < old_coins.vout.size(); ++i) {
534 if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
535 Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase, old_coins.fCoinStake);
537 CoinEntry entry(&outpoint);
538 batch.
Write(entry, newcoin);
557 const auto& p = std::make_pair(checksum, denom);
566 int checksum_height = 0;
const CChainParams & Params()
Return the currently selected parameters.
void Erase(uint32_t checksum, libzerocoin::CoinDenomination denom)
Optional< int > Get(uint32_t checksum, libzerocoin::CoinDenomination denom)
std::map< std::pair< uint32_t, libzerocoin::CoinDenomination >, int > mapCheckpoints
void Set(uint32_t checksum, libzerocoin::CoinDenomination denom, int height)
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
const_iterator end() const
const_iterator begin() const
The block chain is a tree shaped structure starting with the genesis block at the root,...
std::string ToString() const
CBlockIndex * pprev
pointer to the index of the predecessor of this block
std::vector< unsigned char > vStakeModifier
int nFile
Which # file this block is stored in (blk?????.dat)
unsigned int nUndoPos
Byte offset within rev?????.dat where this block's undo data is stored.
uint256 nAccumulatorCheckpoint
uint256 GetBlockHash() const
CAmount nSaplingValue
Change in value held by the Sapling circuit over this block.
unsigned int nTx
Number of transactions in this block.
uint256 hashFinalSaplingRoot
int32_t nVersion
block header
int nHeight
height of the entry in the chain. The genesis block has height 0
uint32_t nStatus
Verification status of this block. See enum BlockStatus.
unsigned int nDataPos
Byte offset within blk?????.dat where this block's data is stored.
bool WriteTxIndex(const std::vector< std::pair< uint256, CDiskTxPos > > &vect)
bool ReadInt(const std::string &name, int &nValue)
bool LoadBlockIndexGuts(std::function< CBlockIndex *(const uint256 &)> insertBlockIndex)
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info)
CBlockTreeDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
bool WriteReindexing(bool fReindexing)
bool WriteBlockIndex(const CDiskBlockIndex &blockindex)
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos)
bool WriteInt(const std::string &name, int nValue)
bool WriteBatchSync(const std::vector< std::pair< int, const CBlockFileInfo * > > &fileInfo, int nLastFile, const std::vector< const CBlockIndex * > &blockinfo)
bool ReadFlag(const std::string &name, bool &fValue)
bool ReadReindexing(bool &fReindexing)
bool ReadLastBlockFile(int &nFile)
bool WriteFlag(const std::string &name, bool fValue)
Cursor for iterating over CoinsView state.
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
std::unique_ptr< CDBIterator > pcursor
bool GetKey(COutPoint &key) const
unsigned int GetValueSize() const
std::pair< char, COutPoint > keyTmp
bool GetValue(Coin &coin) const
CCoinsViewDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether we have data for a given outpoint.
bool Upgrade()
Attempt to update from an older database format. Returns whether an error occurred.
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
bool BatchWriteSapling(const uint256 &hashSaplingAnchor, CAnchorsSaplingMap &mapSaplingAnchors, CNullifiersMap &mapSaplingNullifiers, CDBBatch &batch)
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, const uint256 &hashSaplingAnchor, CAnchorsSaplingMap &mapSaplingAnchors, CNullifiersMap &mapSaplingNullifiers) override
Do a bulk modification (multiple Coin changes + BestBlock change).
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Batch of changes queued to be written to a CDBWrapper.
size_t SizeEstimate() const
void Write(const K &key, const V &value)
CDBIterator * NewIterator()
bool WriteBatch(CDBBatch &batch, bool fSync=false)
bool Read(const K &key, V &value) const
bool Erase(const K &key, bool fSync=false)
bool Write(const K &key, const V &value, bool fSync=false)
bool Exists(const K &key) const
size_t EstimateSize(const K &key_begin, const K &key_end) const
uint256 GetBlockHash() const
An outpoint - a combination of a transaction hash and an index n into its vout.
An output of a transaction.
bool WriteAccChecksum(const uint32_t nChecksum, const libzerocoin::CoinDenomination denom, const int nHeight)
Accumulators (only for zPoS IBD): [checksum, denom] --> block height.
bool ReadCoinSpend(const CBigNum &bnSerial, uint256 &txHash)
bool ReadAccChecksum(const uint32_t nChecksum, const libzerocoin::CoinDenomination denom, int &nHeightRet)
bool EraseAccChecksum(const uint32_t nChecksum, const libzerocoin::CoinDenomination denom)
CZerocoinDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
bool EraseCoinSpend(const CBigNum &bnSerial)
bool WriteCoinSpendBatch(const std::vector< std::pair< CBigNum, uint256 > > &spendInfo)
Write zPIV spends to the zerocoinDB in a batch Pair of: CBigNum -> coinSerialNumber and uint256 -> tx...
bool ReadAll(std::map< std::pair< uint32_t, libzerocoin::CoinDenomination >, int > &mapCheckpoints)
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
std::unordered_map< uint256, CAnchorsSaplingCacheEntry, SaltedIdHasher > CAnchorsSaplingMap
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedOutpointHasher > CCoinsMap
std::unordered_map< uint256, CNullifiersCacheEntry, SaltedIdHasher > CNullifiersMap
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
#define LogPrint(category,...)
boost::optional< T > Optional
Substitute for C++17 std::optional.
bool CheckProofOfWork(uint256 hash, unsigned int nBits)
Check whether a block hash satisfies the proof-of-work requirement specified by nBits.
#define VARINT_MODE(obj, mode)
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
void Unserialize(Stream &s, char &a)
const fs::path & GetDataDir(bool fNetSpecific)
bool error(const char *fmt, const Args &... args)
const uint256 UINT256_ZERO
constant uint256 instances
bool NetworkUpgradeActive(int nHeight, const Consensus::Params ¶ms, Consensus::UpgradeIndex idx)
Returns true if the given network upgrade is active as of the given block height.
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.