Compare commits

...

20 Commits

Author SHA1 Message Date
duke
95b4371aa4 Merge pull request 'Reduce memory usage' (#332) from reduce_memory into dev
Reviewed-on: https://git.hush.is/hush/hush3/pulls/332
2023-10-25 15:11:51 +00:00
Duke
d99ab44bfb Fix implementation of GetBlockHash in CBlockIndex and CDiskBlockIndex 2023-10-23 22:41:29 -04:00
Duke
31a6b72caf Merge branch 'dev' into reduce_memory 2023-10-16 06:04:56 -04:00
Duke
f05cb0cfbd Fix nspv 2023-06-14 00:08:16 -04:00
Duke
13612bb1c8 Better error message when hashPrevBlock != view.GetBestBlock 2023-06-13 22:58:36 -04:00
Duke
31d97c7c9c Spell it correctly 2023-06-13 16:24:54 -04:00
Duke
e993acb2f0 Fix missing hashFinalSaplingRoot in block header 2023-06-13 16:21:25 -04:00
Duke
2525dc6734 Merge branch 'dev' into reduce_memory 2023-06-13 16:08:09 -04:00
Duke
883fbe407f Revert "Add libleveldb-dev to build dependencies"
This reverts commit fab9a7f51d138ec2e2025e7b668d620205ddd070.
2023-04-23 06:23:18 -07:00
Duke
9602e715ed Fix compile issue 2023-04-23 09:13:21 -04:00
Duke
b197c18ffc . 2023-04-23 09:05:51 -04:00
Duke
ca6a1c48bb Make GetBlockHash() calculate the blockhash if phashBlock is null 2023-04-23 06:02:22 -07:00
Duke
cf1274a42a Remove unnecessary consistency checks
As per https://github.com/zcash/zcash/issues/6532 this should speed up
startup times by roughly 3X and drastically reduce disk i/o on startup.
2023-04-20 04:47:20 -07:00
Duke
513ebc5bb4 Say which height we are at when we get an assertion from GetBlockHash 2023-04-19 11:01:20 -04:00
Duke
f8939d2fd9 Fix src/cc compile 2023-04-19 10:38:21 -04:00
Duke
bc1d6be55f Add leveldb/include header dir to src/Makefile.am 2023-04-17 14:32:02 -07:00
Duke
d181029d27 Include path for leveldb when compiling cc #290 2023-04-17 08:46:44 -07:00
Duke
4d6c451314 Try to fix #290 2023-04-17 08:38:30 -07:00
onryo
fab9a7f51d Add libleveldb-dev to build dependencies
Fixes "leveldb/db.h: No such file or directory" error.
2023-04-16 15:53:48 +00:00
Duke
e8dc755f06 Reduce memory usage of CBlockIndex
Ported code from https://github.com/zcash/zcash/pull/6192 with various changes needed
for the Hush codebase.
2023-04-13 23:30:23 -04:00
13 changed files with 192 additions and 60 deletions

View File

@ -39,6 +39,7 @@ BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/include
BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src
BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src/asn BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src/asn
BITCOIN_INCLUDES += -I$(srcdir)/univalue/include BITCOIN_INCLUDES += -I$(srcdir)/univalue/include
BITCOIN_INCLUDES += -I$(srcdir)/leveldb/include
if TARGET_WINDOWS if TARGET_WINDOWS
LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl

View File

@ -3,9 +3,9 @@ CC = gcc
CC_DARWIN = g++-6 CC_DARWIN = g++-6
CC_WIN = x86_64-w64-mingw32-gcc-posix CC_WIN = x86_64-w64-mingw32-gcc-posix
CFLAGS = -arch x86_64 CFLAGS = -arch x86_64
CXXFLAGS_DARWIN = -std=c++11 -arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -c -Wl,-undefined -Wl,dynamic_lookup -dynamiclib CXXFLAGS_DARWIN = -std=c++11 -arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I -I../leveldb/include -I.. -I. -fPIC -c -Wl,-undefined -Wl,dynamic_lookup -dynamiclib
CXXFLAGS = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c CXXFLAGS = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I../leveldb/include -I.. -I. -fPIC -shared -c
CXXFLAGS_WIN = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c CXXFLAGS_WIN = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I../leveldb/include -I.. -I. -fPIC -shared -c
DEBUGFLAGS = -O0 -D _DEBUG DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
$(info $(OS)) $(info $(OS))

View File

@ -3,9 +3,9 @@ CC = gcc
CC_DARWIN = g++-8 CC_DARWIN = g++-8
CC_WIN = x86_64-w64-mingw32-gcc-posix CC_WIN = x86_64-w64-mingw32-gcc-posix
CC_AARCH64 = aarch64-linux-gnu-g++ CC_AARCH64 = aarch64-linux-gnu-g++
CFLAGS_DARWIN = -DBUILD_CUSTOMCC -std=c++11 -arch x86_64 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib CFLAGS_DARWIN = -DBUILD_CUSTOMCC -std=c++11 -arch x86_64 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I../leveldb/include -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib
CFLAGS = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared CFLAGS = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I../leveldb/include -I.. -I. -fPIC -shared
CFLAGS_WIN = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/x86_64-w64-mingw32/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared CFLAGS_WIN = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/x86_64-w64-mingw32/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I../leveldb/include -I.. -I. -fPIC -shared
DEBUGFLAGS = -O0 -D _DEBUG DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
$(info $(OS)) $(info $(OS))

View File

@ -19,12 +19,56 @@
******************************************************************************/ ******************************************************************************/
#include "chain.h" #include "chain.h"
#include "main.h"
#include "txdb.h"
using namespace std; using namespace std;
/** /**
* CChain implementation * CChain implementation
*/ */
void CBlockIndex::TrimSolution()
{
AssertLockHeld(cs_main);
// We can correctly trim a solution as soon as the block index entry has been added
// to leveldb. Updates to the block index entry (to update validity status) will be
// handled by re-reading the solution from the existing db entry. It does not help to
// try to avoid these reads by gating trimming on the validity status: the re-reads are
// efficient anyway because of caching in leveldb, and most of them are unavoidable.
if (HasSolution()) {
std::vector<unsigned char> empty;
nSolution.swap(empty);
}
}
CBlockHeader CBlockIndex::GetBlockHeader() const
{
AssertLockHeld(cs_main);
CBlockHeader header;
header.nVersion = nVersion;
if (pprev) {
header.hashPrevBlock = pprev->GetBlockHash();
}
header.hashMerkleRoot = hashMerkleRoot;
header.hashFinalSaplingRoot = hashFinalSaplingRoot;
header.nTime = nTime;
header.nBits = nBits;
header.nNonce = nNonce;
if (HasSolution()) {
header.nSolution = nSolution;
} else {
CDiskBlockIndex dbindex;
if (!pblocktree->ReadDiskBlockIndex(GetBlockHash(), dbindex)) {
LogPrintf("%s: ReadDiskBlockIndex failed to read index entry of block %s", __func__, GetBlockHash().ToString().c_str());
throw std::runtime_error("Failed to read index entry");
}
header.nSolution = dbindex.GetSolution();
}
return header;
}
void CChain::SetTip(CBlockIndex *pindex) { void CChain::SetTip(CBlockIndex *pindex) {
lastTip = pindex; lastTip = pindex;
if (pindex == NULL) { if (pindex == NULL) {

View File

@ -27,6 +27,7 @@ class CChainPower;
#include "pow.h" #include "pow.h"
#include "tinyformat.h" #include "tinyformat.h"
#include "uint256.h" #include "uint256.h"
#include "util/strencodings.h"
#include <vector> #include <vector>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -384,8 +385,14 @@ public:
unsigned int nTime; unsigned int nTime;
unsigned int nBits; unsigned int nBits;
uint256 nNonce; uint256 nNonce;
protected:
// The Equihash solution, if it is stored. Once we know that the block index
// entry is present in leveldb, this field can be cleared via the TrimSolution
// method to save memory.
std::vector<unsigned char> nSolution; std::vector<unsigned char> nSolution;
public:
//! (memory only) Sequential id assigned to distinguish order in which blocks are received. //! (memory only) Sequential id assigned to distinguish order in which blocks are received.
uint32_t nSequenceId; uint32_t nSequenceId;
@ -497,23 +504,15 @@ public:
return ret; return ret;
} }
CBlockHeader GetBlockHeader() const //! Get the block header for this block index. Requires cs_main.
{ CBlockHeader GetBlockHeader() const;
CBlockHeader block;
block.nVersion = nVersion; //! Clear the Equihash solution to save memory. Requires cs_main.
if (pprev) void TrimSolution();
block.hashPrevBlock = pprev->GetBlockHash();
block.hashMerkleRoot = hashMerkleRoot;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
block.nSolution = nSolution;
return block;
}
uint256 GetBlockHash() const uint256 GetBlockHash() const
{ {
assert(phashBlock);
return *phashBlock; return *phashBlock;
} }
@ -540,10 +539,11 @@ public:
std::string ToString() const std::string ToString() const
{ {
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s, HasSolution=%s)",
pprev, this->chainPower.nHeight, pprev, this->chainPower.nHeight,
hashMerkleRoot.ToString(), hashMerkleRoot.ToString(),
GetBlockHash().ToString()); phashBlock ? GetBlockHash().ToString() : "(nil)",
HasSolution());
} }
//! Check whether this block index entry is valid up to the passed validity level. //! Check whether this block index entry is valid up to the passed validity level.
@ -555,6 +555,12 @@ public:
return ((nStatus & BLOCK_VALID_MASK) >= nUpTo); return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);
} }
//! Is the Equihash solution stored?
bool HasSolution() const
{
return !nSolution.empty();
}
//! Raise the validity level of this block index entry. //! Raise the validity level of this block index entry.
//! Returns true if the validity was changed. //! Returns true if the validity was changed.
bool RaiseValidity(enum BlockStatus nUpTo) bool RaiseValidity(enum BlockStatus nUpTo)
@ -588,8 +594,11 @@ public:
hashPrev = uint256(); hashPrev = uint256();
} }
explicit CDiskBlockIndex(const CBlockIndex* pindex) : CBlockIndex(*pindex) { explicit CDiskBlockIndex(const CBlockIndex* pindex, std::function<std::vector<unsigned char>()> getSolution) : CBlockIndex(*pindex) {
hashPrev = (pprev ? pprev->GetBlockHash() : uint256()); hashPrev = (pprev ? pprev->GetBlockHash() : uint256());
if (!HasSolution()) {
nSolution = getSolution();
}
} }
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@ -670,18 +679,29 @@ public:
uint256 GetBlockHash() const uint256 GetBlockHash() const
{ {
CBlockHeader block; return GetBlockHeader().GetHash();
block.nVersion = nVersion;
block.hashPrevBlock = hashPrev;
block.hashMerkleRoot = hashMerkleRoot;
block.hashFinalSaplingRoot = hashFinalSaplingRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
block.nSolution = nSolution;
return block.GetHash();
} }
//! Get the block header for this block index.
CBlockHeader GetBlockHeader() const
{
CBlockHeader header;
header.nVersion = nVersion;
header.hashPrevBlock = hashPrev;
header.hashMerkleRoot = hashMerkleRoot;
header.hashFinalSaplingRoot = hashFinalSaplingRoot;
header.nTime = nTime;
header.nBits = nBits;
header.nNonce = nNonce;
header.nSolution = nSolution;
return header;
}
std::vector<unsigned char> GetSolution() const
{
assert(HasSolution());
return nSolution;
}
std::string ToString() const std::string ToString() const
{ {
@ -692,6 +712,13 @@ public:
hashPrev.ToString()); hashPrev.ToString());
return str; return str;
} }
private:
//! This method should not be called on a CDiskBlockIndex.
void TrimSolution()
{
assert(!"called CDiskBlockIndex::TrimSolution");
}
}; };
/** An in-memory indexed chain of blocks. */ /** An in-memory indexed chain of blocks. */

View File

@ -12,8 +12,8 @@
#include "util.h" #include "util.h"
#include "version.h" #include "version.h"
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <leveldb/db.h> #include "leveldb/db.h"
#include <leveldb/write_batch.h> #include "leveldb/write_batch.h"
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;

View File

@ -124,7 +124,8 @@ int32_t NSPV_setequihdr(struct NSPV_equihdr *hdr,int32_t height)
hdr->nTime = pindex->nTime; hdr->nTime = pindex->nTime;
hdr->nBits = pindex->nBits; hdr->nBits = pindex->nBits;
hdr->nNonce = pindex->nNonce; hdr->nNonce = pindex->nNonce;
memcpy(hdr->nSolution,&pindex->nSolution[0],sizeof(hdr->nSolution));
memcpy(hdr->nSolution,&pindex->GetBlockHeader().nSolution[0],sizeof(hdr->nSolution));
return(sizeof(*hdr)); return(sizeof(*hdr));
} }
return(-1); return(-1);

View File

@ -3254,7 +3254,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash();
if ( hashPrevBlock != view.GetBestBlock() ) if ( hashPrevBlock != view.GetBestBlock() )
{ {
fprintf(stderr,"ConnectBlock(): hashPrevBlock != view.GetBestBlock()\n"); fprintf(stderr,"ConnectBlock(): hashPrevBlock != view.GetBestBlock() %s != %s\n", hashPrevBlock.ToString().c_str(), view.GetBestBlock().ToString().c_str() );
return state.DoS(1, error("ConnectBlock(): hashPrevBlock != view.GetBestBlock()"), return state.DoS(1, error("ConnectBlock(): hashPrevBlock != view.GetBestBlock()"),
REJECT_INVALID, "hashPrevBlock-not-bestblock"); REJECT_INVALID, "hashPrevBlock-not-bestblock");
} }
@ -3700,7 +3701,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it]));
setDirtyFileInfo.erase(it++); setDirtyFileInfo.erase(it++);
} }
std::vector<const CBlockIndex*> vBlocks; std::vector<CBlockIndex*> vBlocks;
vBlocks.reserve(setDirtyBlockIndex.size()); vBlocks.reserve(setDirtyBlockIndex.size());
for (set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { for (set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) {
vBlocks.push_back(*it); vBlocks.push_back(*it);
@ -3709,6 +3710,12 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
return AbortNode(state, "Files to write to block index database"); return AbortNode(state, "Files to write to block index database");
} }
// Now that we have written the block indices to the database, we do not
// need to store solutions for these CBlockIndex objects in memory.
// cs_main must be held here.
for (CBlockIndex *pblockindex : vBlocks) {
pblockindex->TrimSolution();
}
} }
// Finally remove any pruned files // Finally remove any pruned files
if (fFlushForPrune) if (fFlushForPrune)
@ -6591,7 +6598,11 @@ void static CheckBlockIndex()
} }
} }
} }
// try {
// assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
// } catch (const runtime_error&) {
// assert(!"Failed to read index entry");
// }
// End: actual consistency checks. // End: actual consistency checks.
// Try descending into the first subnode. // Try descending into the first subnode.

View File

@ -39,6 +39,7 @@
#include "spentindex.h" #include "spentindex.h"
#include "sync.h" #include "sync.h"
#include "tinyformat.h" #include "tinyformat.h"
#include "txdb.h"
#include "txmempool.h" #include "txmempool.h"
#include "uint256.h" #include "uint256.h"

View File

@ -151,6 +151,7 @@ static bool rest_headers(HTTPRequest* req,
std::vector<const CBlockIndex *> headers; std::vector<const CBlockIndex *> headers;
headers.reserve(count); headers.reserve(count);
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
{ {
LOCK(cs_main); LOCK(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash); BlockMap::const_iterator it = mapBlockIndex.find(hash);
@ -161,12 +162,17 @@ static bool rest_headers(HTTPRequest* req,
break; break;
pindex = chainActive.Next(pindex); pindex = chainActive.Next(pindex);
} }
}
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); if (rf == RF_BINARY || rf == RF_HEX) {
BOOST_FOREACH(const CBlockIndex *pindex, headers) { try {
for (const CBlockIndex *pindex : headers) {
ssHeader << pindex->GetBlockHeader(); ssHeader << pindex->GetBlockHeader();
} }
} catch (const std::runtime_error&) {
return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Failed to read index entry");
}
}
}
switch (rf) { switch (rf) {
case RF_BINARY: { case RF_BINARY: {

View File

@ -147,7 +147,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
result.push_back(Pair("finalsaplingroot", blockindex->hashFinalSaplingRoot.GetHex())); result.push_back(Pair("finalsaplingroot", blockindex->hashFinalSaplingRoot.GetHex()));
result.push_back(Pair("time", (int64_t)blockindex->nTime)); result.push_back(Pair("time", (int64_t)blockindex->nTime));
result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); result.push_back(Pair("nonce", blockindex->nNonce.GetHex()));
result.push_back(Pair("solution", HexStr(blockindex->nSolution))); result.pushKV("solution", HexStr(blockindex->GetBlockHeader().nSolution));
result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->chainPower.chainWork.GetHex())); result.push_back(Pair("chainwork", blockindex->chainPower.chainWork.GetHex()));
@ -693,15 +693,18 @@ UniValue getblockheader(const UniValue& params, bool fHelp, const CPubKey& mypk)
CBlockIndex* pblockindex = mapBlockIndex[hash]; CBlockIndex* pblockindex = mapBlockIndex[hash];
if (!fVerbose) try {
{ if (!fVerbose) {
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << pblockindex->GetBlockHeader(); ssBlock << pblockindex->GetBlockHeader();
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
return strHex; return strHex;
} } else {
return blockheaderToJSON(pblockindex); return blockheaderToJSON(pblockindex);
}
} catch (const runtime_error&) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Failed to read index entry");
}
} }
UniValue getblock(const UniValue& params, bool fHelp, const CPubKey& mypk) UniValue getblock(const UniValue& params, bool fHelp, const CPubKey& mypk)

View File

@ -269,18 +269,33 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
return true; return true;
} }
bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) { bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<CBlockIndex*>& blockinfo) {
CDBBatch batch(*this); CDBBatch batch(*this);
if (fZdebug) if (fZdebug)
fprintf(stderr, "%s: Writing block files\n", __FUNCTION__); fprintf(stderr, "%s: Writing block files\n", __FUNCTION__);
for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { for (const auto& it : fileInfo) {
batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second); batch.Write(make_pair(DB_BLOCK_FILES, it.first), *it.second);
} }
batch.Write(DB_LAST_BLOCK, nLastFile); batch.Write(DB_LAST_BLOCK, nLastFile);
if (fZdebug) if (fZdebug)
fprintf(stderr, "%s: Writing block index\n", __FUNCTION__); fprintf(stderr, "%s: Writing block index\n", __FUNCTION__);
for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) { for (const auto& it : blockinfo) {
batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it)); std::pair<char, uint256> key = make_pair(DB_BLOCK_INDEX, it->GetBlockHash());
try {
CDiskBlockIndex dbindex {it, [this, &key]() {
// It can happen that the index entry is written, then the Equihash solution is cleared from memory,
// then the index entry is rewritten. In that case we must read the solution from the old entry.
CDiskBlockIndex dbindex_old;
if (!Read(key, dbindex_old)) {
LogPrintf("%s: Failed to read index entry", __func__);
throw runtime_error("Failed to read index entry");
}
return dbindex_old.GetSolution();
}};
batch.Write(key, dbindex);
} catch (const runtime_error&) {
return false;
}
} }
return WriteBatch(batch, true); return WriteBatch(batch, true);
} }
@ -293,6 +308,11 @@ bool CBlockTreeDB::EraseBatchSync(const std::vector<const CBlockIndex*>& blockin
return WriteBatch(batch, true); return WriteBatch(batch, true);
} }
bool CBlockTreeDB::ReadDiskBlockIndex(const uint256 &blockhash, CDiskBlockIndex &dbindex) const {
return Read(make_pair(DB_BLOCK_INDEX, blockhash), dbindex);
}
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) const { bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) const {
return Read(make_pair(DB_TXINDEX, txid), pos); return Read(make_pair(DB_TXINDEX, txid), pos);
} }
@ -692,7 +712,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nTime = diskindex.nTime; pindexNew->nTime = diskindex.nTime;
pindexNew->nBits = diskindex.nBits; pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce; pindexNew->nNonce = diskindex.nNonce;
pindexNew->nSolution = diskindex.nSolution; // the Equihash solution will be loaded lazily from the dbindex entry
// pindexNew->nSolution = diskindex.nSolution;
pindexNew->nStatus = diskindex.nStatus; pindexNew->nStatus = diskindex.nStatus;
pindexNew->nCachedBranchId = diskindex.nCachedBranchId; pindexNew->nCachedBranchId = diskindex.nCachedBranchId;
pindexNew->nTx = diskindex.nTx; pindexNew->nTx = diskindex.nTx;
@ -716,10 +737,24 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
//fprintf(stderr,"loadguts ht.%d\n",pindexNew->GetHeight()); //fprintf(stderr,"loadguts ht.%d\n",pindexNew->GetHeight());
// Consistency checks // Consistency checks
auto header = pindexNew->GetBlockHeader(); /*
CBlockHeader header;
{
LOCK(cs_main);
try {
header = pindexNew->GetBlockHeader();
} catch (const runtime_error&) {
return error("LoadBlockIndex(): failed to read index entry: diskindex hash = %s",
diskindex.GetBlockHash().ToString());
}
}
if (header.GetHash() != diskindex.GetBlockHash())
return error("LoadBlockIndex(): inconsistent header vs diskindex hash: header hash = %s, diskindex hash = %s",
header.GetHash().ToString(), diskindex.GetBlockHash().ToString());
if (header.GetHash() != pindexNew->GetBlockHash()) if (header.GetHash() != pindexNew->GetBlockHash())
return error("LoadBlockIndex(): block header inconsistency detected: on-disk = %s, in-memory = %s", return error("LoadBlockIndex(): block header inconsistency detected: on-disk = %s, in-memory = %s",
diskindex.ToString(), pindexNew->ToString()); diskindex.ToString(), pindexNew->ToString());
if ( 0 ) // POW will be checked before any block is connected if ( 0 ) // POW will be checked before any block is connected
{ {
uint8_t pubkey33[33]; uint8_t pubkey33[33];
@ -727,6 +762,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
if (!CheckProofOfWork(header,pubkey33,pindexNew->GetHeight(),Params().GetConsensus())) if (!CheckProofOfWork(header,pubkey33,pindexNew->GetHeight(),Params().GetConsensus()))
return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
} }
*/
pcursor->Next(); pcursor->Next();
} else { } else {
return error("LoadBlockIndex() : failed to read value"); return error("LoadBlockIndex() : failed to read value");

View File

@ -26,6 +26,7 @@
#include "coins.h" #include "coins.h"
#include "dbwrapper.h" #include "dbwrapper.h"
#include "chain.h"
#include <map> #include <map>
#include <string> #include <string>
#include <utility> #include <utility>
@ -91,12 +92,13 @@ private:
CBlockTreeDB(const CBlockTreeDB&); CBlockTreeDB(const CBlockTreeDB&);
void operator=(const CBlockTreeDB&); void operator=(const CBlockTreeDB&);
public: public:
bool WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo); bool WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<CBlockIndex*>& blockinfo);
bool EraseBatchSync(const std::vector<const CBlockIndex*>& blockinfo); bool EraseBatchSync(const std::vector<const CBlockIndex*>& blockinfo);
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo) const; bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo) const;
bool ReadLastBlockFile(int &nFile) const; bool ReadLastBlockFile(int &nFile) const;
bool WriteReindexing(bool fReindex); bool WriteReindexing(bool fReindex);
bool ReadReindexing(bool &fReindex) const; bool ReadReindexing(bool &fReindex) const;
bool ReadDiskBlockIndex(const uint256 &blockhash, CDiskBlockIndex &dbindex) const;
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) const; bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) const;
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list); bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) const; bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) const;