Support auxillary proof of work.
Rebased from 1.7.1 into 1.7.2, moved AuxPoW checks from AcceptBlock() into AcceptBlockHeader()
This commit is contained in:
parent
e87673bd38
commit
8808f237aa
|
@ -29,6 +29,7 @@ DIST_SUBDIRS = . qt test
|
|||
BITCOIN_CORE_H = \
|
||||
addrman.h \
|
||||
alert.h \
|
||||
auxpow.h \
|
||||
allocators.h \
|
||||
base58.h bignum.h \
|
||||
bloom.h \
|
||||
|
@ -93,6 +94,7 @@ version.o: obj/build.h
|
|||
libbitcoin_server_a_SOURCES = \
|
||||
addrman.cpp \
|
||||
alert.cpp \
|
||||
auxpow.cpp \
|
||||
bloom.cpp \
|
||||
checkpoints.cpp \
|
||||
coins.cpp \
|
||||
|
|
|
@ -4,9 +4,16 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "core.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
int GetOurChainID()
|
||||
{
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
std::string COutPoint::ToString() const
|
||||
{
|
||||
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
|
||||
|
|
45
src/core.h
45
src/core.h
|
@ -17,10 +17,34 @@
|
|||
#include <stdint.h>
|
||||
|
||||
class CTransaction;
|
||||
class CAuxPow;
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionSerialize ser_action);
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionUnserialize ser_action);
|
||||
|
||||
template <typename Stream>
|
||||
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionGetSerializeSize ser_action);
|
||||
|
||||
enum
|
||||
{
|
||||
// primary version
|
||||
BLOCK_VERSION_DEFAULT = (1 << 0),
|
||||
|
||||
// modifiers
|
||||
BLOCK_VERSION_AUXPOW = (1 << 8),
|
||||
|
||||
// bits allocated for chain ID
|
||||
BLOCK_VERSION_CHAIN_START = (1 << 16),
|
||||
BLOCK_VERSION_CHAIN_END = (1 << 30),
|
||||
};
|
||||
|
||||
/** No amount larger than this (in satoshi) is valid */
|
||||
static const int64_t MAX_MONEY = 10000000000 * COIN; // Dogecoin: maximum of 100B coins (given some randomness), max transaction 10,000,000,000
|
||||
inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
|
||||
int GetOurChainID();
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
|
@ -350,6 +374,7 @@ public:
|
|||
unsigned int nTime;
|
||||
unsigned int nBits;
|
||||
unsigned int nNonce;
|
||||
boost::shared_ptr<CAuxPow> auxpow;
|
||||
|
||||
CBlockHeader()
|
||||
{
|
||||
|
@ -365,11 +390,27 @@ public:
|
|||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
READWRITE(nNonce);
|
||||
|
||||
nSerSize += ReadWriteAuxPow(s, auxpow, nType, nVersion, ser_action);
|
||||
)
|
||||
|
||||
int GetChainID() const
|
||||
{
|
||||
return nVersion / BLOCK_VERSION_CHAIN_START;
|
||||
}
|
||||
|
||||
uint256 GetPoWHash() const
|
||||
{
|
||||
uint256 thash;
|
||||
scrypt_1024_1_1_256(BEGIN(nVersion), BEGIN(thash));
|
||||
return thash;
|
||||
}
|
||||
|
||||
void SetAuxPow(CAuxPow* pow);
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nVersion = CBlockHeader::CURRENT_VERSION;
|
||||
nVersion = CBlockHeader::CURRENT_VERSION | (GetOurChainID() * BLOCK_VERSION_CHAIN_START);
|
||||
hashPrevBlock = 0;
|
||||
hashMerkleRoot = 0;
|
||||
nTime = 0;
|
||||
|
@ -395,6 +436,8 @@ public:
|
|||
{
|
||||
return (int64_t)nTime;
|
||||
}
|
||||
|
||||
bool CheckProofOfWork(int nHeight) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
137
src/main.cpp
137
src/main.cpp
|
@ -14,6 +14,7 @@
|
|||
#include "checkpoints.h"
|
||||
#include "checkqueue.h"
|
||||
#include "init.h"
|
||||
#include "auxpow.h"
|
||||
#include "net.h"
|
||||
#include "txdb.h"
|
||||
#include "txmempool.h"
|
||||
|
@ -1133,7 +1134,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
|
|||
}
|
||||
|
||||
// Check the header
|
||||
if (!CheckProofOfWork(block.GetPoWHash(), block.nBits))
|
||||
if (!block.CheckProofOfWork(mapBlockIndex[block.GetHash()]->nHeight))
|
||||
return error("ReadBlockFromDisk : Errors in block header");
|
||||
|
||||
return true;
|
||||
|
@ -1148,6 +1149,15 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CBlockHeader::SetAuxPow(CAuxPow* pow)
|
||||
{
|
||||
if (pow != NULL)
|
||||
nVersion |= BLOCK_VERSION_AUXPOW;
|
||||
else
|
||||
nVersion &= ~BLOCK_VERSION_AUXPOW;
|
||||
auxpow.reset(pow);
|
||||
}
|
||||
|
||||
uint256 static GetOrphanRoot(const uint256& hash)
|
||||
{
|
||||
map<uint256, COrphanBlock*>::iterator it = mapOrphanBlocks.find(hash);
|
||||
|
@ -1543,7 +1553,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
|
|||
}
|
||||
if (!state.CorruptionPossible()) {
|
||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
|
||||
pblocktree->WriteBlockIndex(*pindex);
|
||||
setBlockIndexValid.erase(pindex);
|
||||
InvalidChainFound(pindex);
|
||||
}
|
||||
|
@ -1840,7 +1850,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Check it again in case a previous version let a bad block in
|
||||
if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
|
||||
if (!CheckBlock(block, state, pindex->nHeight, !fJustCheck, !fJustCheck))
|
||||
return false;
|
||||
|
||||
// verify that the view's current state corresponds to the previous block
|
||||
|
@ -1985,8 +1995,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|||
|
||||
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
|
||||
|
||||
CDiskBlockIndex blockindex(pindex);
|
||||
if (!pblocktree->WriteBlockIndex(blockindex))
|
||||
if (!pblocktree->WriteBlockIndex(*pindex))
|
||||
return state.Abort(_("Failed to write block index"));
|
||||
}
|
||||
|
||||
|
@ -2312,7 +2321,8 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
|
|||
if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS))
|
||||
setBlockIndexValid.insert(pindexNew);
|
||||
|
||||
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
|
||||
/* write both the immutible data (CDiskBlockIndex) and the mutable data (BlockIndex) */
|
||||
if (!pblocktree->WriteDiskBlockIndex(CDiskBlockIndex(pindexNew, block.auxpow)) || !pblocktree->WriteBlockIndex(*pindexNew))
|
||||
return state.Abort(_("Failed to write block index"));
|
||||
|
||||
// New best?
|
||||
|
@ -2338,6 +2348,58 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
|
|||
return true;
|
||||
}
|
||||
|
||||
// to enable merged mining:
|
||||
// - set a block from which it will be enabled
|
||||
// - set a unique chain ID
|
||||
// each merged minable scrypt_1024_1_1_256 coin should have a different one
|
||||
// (if two have the same ID, they can't be merge mined together)
|
||||
int GetAuxPowStartBlock()
|
||||
{
|
||||
if (TestNet())
|
||||
return INT_MAX; // never
|
||||
else
|
||||
return INT_MAX; // never
|
||||
}
|
||||
|
||||
bool CBlockHeader::CheckProofOfWork(int nHeight) const
|
||||
{
|
||||
if (nHeight >= GetAuxPowStartBlock())
|
||||
{
|
||||
// Prevent same work from being submitted twice:
|
||||
// - this block must have our chain ID
|
||||
// - parent block must not have the same chain ID (see CAuxPow::Check)
|
||||
// - index of this chain in chain merkle tree must be pre-determined (see CAuxPow::Check)
|
||||
if (!TestNet() && nHeight != INT_MAX && GetChainID() != GetOurChainID())
|
||||
return error("CheckProofOfWork() : block does not have our chain ID");
|
||||
|
||||
if (auxpow.get() != NULL)
|
||||
{
|
||||
if (!auxpow->Check(GetHash(), GetChainID()))
|
||||
return error("CheckProofOfWork() : AUX POW is not valid");
|
||||
// Check proof of work matches claimed amount
|
||||
if (!::CheckProofOfWork(auxpow->GetParentBlockHash(), nBits))
|
||||
return error("CheckProofOfWork() : AUX proof of work failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check proof of work matches claimed amount
|
||||
if (!::CheckProofOfWork(GetPoWHash(), nBits))
|
||||
return error("CheckProofOfWork() : proof of work failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auxpow.get() != NULL)
|
||||
{
|
||||
return error("CheckProofOfWork() : AUX POW is not allowed at this block");
|
||||
}
|
||||
|
||||
// Check if proof of work marches claimed amount
|
||||
if (!::CheckProofOfWork(GetPoWHash(), nBits))
|
||||
return error("CheckProofOfWork() : proof of work failed");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
|
||||
{
|
||||
|
@ -2433,11 +2495,10 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, int nHeight, bool fCheckPOW)
|
||||
{
|
||||
// Check proof of work matches claimed amount
|
||||
if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits))
|
||||
if (fCheckPOW && !block.CheckProofOfWork(nHeight))
|
||||
return state.DoS(50, error("CheckBlockHeader() : proof of work failed"),
|
||||
REJECT_INVALID, "high-hash");
|
||||
|
||||
|
@ -2470,12 +2531,12 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, int nHeight, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||
{
|
||||
// These are checks that are independent of context
|
||||
// that can be verified before saving an orphan block.
|
||||
|
||||
if (!CheckBlockHeader(block, state, fCheckPOW))
|
||||
if (!CheckBlockHeader(block, state, nHeight, fCheckPOW))
|
||||
return false;
|
||||
|
||||
// Size limits
|
||||
|
@ -2602,14 +2663,15 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
|||
if (!AcceptBlockHeader(block, state, &pindex))
|
||||
return false;
|
||||
|
||||
if (!CheckBlock(block, state)) {
|
||||
int nHeight = pindex->nHeight;
|
||||
|
||||
if (!CheckBlock(block, state, nHeight)) {
|
||||
if (state.Invalid() && !state.CorruptionPossible()) {
|
||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int nHeight = pindex->nHeight;
|
||||
uint256 hash = pindex->GetBlockHash();
|
||||
|
||||
// Check that all transactions are finalized
|
||||
|
@ -2695,6 +2757,48 @@ int64_t CBlockIndex::GetMedianTime() const
|
|||
return pindex->GetMedianTimePast();
|
||||
}
|
||||
|
||||
std::string CBlockIndex::ToString() const
|
||||
{
|
||||
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
|
||||
pprev, nHeight,
|
||||
hashMerkleRoot.ToString().substr(0,10).c_str(),
|
||||
GetBlockHash().ToString().c_str());
|
||||
}
|
||||
|
||||
std::string CDiskBlockIndex::ToString() const
|
||||
{
|
||||
std::string str = "CDiskBlockIndex(";
|
||||
str += CBlockIndex::ToString();
|
||||
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashParentBlock=%s)",
|
||||
GetBlockHash().ToString().c_str(),
|
||||
hashPrev.ToString().c_str(),
|
||||
(auxpow.get() != NULL) ? auxpow->GetParentBlockHash().ToString().substr(0,20).c_str() : "-");
|
||||
return str;
|
||||
}
|
||||
|
||||
CBlockHeader CBlockIndex::GetBlockHeader() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
|
||||
if (nVersion & BLOCK_VERSION_AUXPOW) {
|
||||
CDiskBlockIndex diskblockindex;
|
||||
// auxpow is not in memory, load CDiskBlockHeader
|
||||
// from database to get it
|
||||
|
||||
pblocktree->ReadDiskBlockIndex(*phashBlock, diskblockindex);
|
||||
block.auxpow = diskblockindex.auxpow;
|
||||
}
|
||||
|
||||
block.nVersion = nVersion;
|
||||
if (pprev)
|
||||
block.hashPrevBlock = pprev->GetBlockHash();
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block;
|
||||
}
|
||||
|
||||
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
@ -2719,8 +2823,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString()), 0, "duplicate");
|
||||
|
||||
// Preliminary checks
|
||||
if (!CheckBlock(*pblock, state))
|
||||
if (!CheckBlock(*pblock, state, INT_MAX)) {
|
||||
if (state.CorruptionPossible())
|
||||
mapAlreadyAskedFor.erase(CInv(MSG_BLOCK, hash));
|
||||
return error("ProcessBlock() : CheckBlock FAILED");
|
||||
}
|
||||
|
||||
// If we don't already have its previous block (with full data), shunt it off to holding area until we get it
|
||||
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
|
||||
|
@ -3098,7 +3205,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
|||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
// check level 1: verify block validity
|
||||
if (nCheckLevel >= 1 && !CheckBlock(block, state))
|
||||
if (nCheckLevel >= 1 && !CheckBlock(block, state, pindex->nHeight))
|
||||
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||
// check level 2: verify undo validity
|
||||
if (nCheckLevel >= 2 && pindex) {
|
||||
|
|
70
src/main.h
70
src/main.h
|
@ -622,8 +622,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
|||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
||||
|
||||
// Context-independent validity checks
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, int nHeight, bool fCheckPOW = true);
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, int nHeight, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
|
||||
// Store block on disk
|
||||
// if dbp is provided, the file is known to already reside on disk
|
||||
|
@ -794,6 +794,22 @@ public:
|
|||
nNonce = block.nNonce;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
/* mutable stuff goes here, immutable stuff
|
||||
* has SERIALIZE functions in CDiskBlockIndex */
|
||||
if (!(nType & SER_GETHASH))
|
||||
READWRITE(VARINT(nVersion));
|
||||
|
||||
READWRITE(VARINT(nStatus));
|
||||
if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
|
||||
READWRITE(VARINT(nFile));
|
||||
if (nStatus & BLOCK_HAVE_DATA)
|
||||
READWRITE(VARINT(nDataPos));
|
||||
if (nStatus & BLOCK_HAVE_UNDO)
|
||||
READWRITE(VARINT(nUndoPos));
|
||||
)
|
||||
|
||||
CDiskBlockPos GetBlockPos() const {
|
||||
CDiskBlockPos ret;
|
||||
if (nStatus & BLOCK_HAVE_DATA) {
|
||||
|
@ -812,18 +828,7 @@ public:
|
|||
return ret;
|
||||
}
|
||||
|
||||
CBlockHeader GetBlockHeader() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
if (pprev)
|
||||
block.hashPrevBlock = pprev->GetBlockHash();
|
||||
block.hashMerkleRoot = hashMerkleRoot;
|
||||
block.nTime = nTime;
|
||||
block.nBits = nBits;
|
||||
block.nNonce = nNonce;
|
||||
return block;
|
||||
}
|
||||
CBlockHeader GetBlockHeader() const;
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
{
|
||||
|
@ -876,13 +881,7 @@ public:
|
|||
static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart,
|
||||
unsigned int nRequired, unsigned int nToCheck);
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
|
||||
pprev, nHeight,
|
||||
hashMerkleRoot.ToString().c_str(),
|
||||
GetBlockHash().ToString().c_str());
|
||||
}
|
||||
std::string ToString() const; //moved code to main.cpp because new method required access to auxpow
|
||||
|
||||
void print() const
|
||||
{
|
||||
|
@ -921,28 +920,28 @@ class CDiskBlockIndex : public CBlockIndex
|
|||
public:
|
||||
uint256 hashPrev;
|
||||
|
||||
// if this is an aux work block
|
||||
boost::shared_ptr<CAuxPow> auxpow;
|
||||
|
||||
CDiskBlockIndex() {
|
||||
hashPrev = 0;
|
||||
auxpow.reset();
|
||||
}
|
||||
|
||||
explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) {
|
||||
explicit CDiskBlockIndex(CBlockIndex* pindex, boost::shared_ptr<CAuxPow> auxpow) : CBlockIndex(*pindex) {
|
||||
hashPrev = (pprev ? pprev->GetBlockHash() : 0);
|
||||
this->auxpow = auxpow;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIALIZE
|
||||
(
|
||||
/* immutable stuff goes here, mutable stuff
|
||||
* has SERIALIZE functions in CBlockIndex */
|
||||
if (!(nType & SER_GETHASH))
|
||||
READWRITE(VARINT(nVersion));
|
||||
|
||||
READWRITE(VARINT(nHeight));
|
||||
READWRITE(VARINT(nStatus));
|
||||
READWRITE(VARINT(nTx));
|
||||
if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
|
||||
READWRITE(VARINT(nFile));
|
||||
if (nStatus & BLOCK_HAVE_DATA)
|
||||
READWRITE(VARINT(nDataPos));
|
||||
if (nStatus & BLOCK_HAVE_UNDO)
|
||||
READWRITE(VARINT(nUndoPos));
|
||||
|
||||
// block header
|
||||
READWRITE(this->nVersion);
|
||||
|
@ -951,9 +950,10 @@ public:
|
|||
READWRITE(nTime);
|
||||
READWRITE(nBits);
|
||||
READWRITE(nNonce);
|
||||
ReadWriteAuxPow(s, auxpow, nType, this->nVersion, ser_action);
|
||||
)
|
||||
|
||||
uint256 GetBlockHash() const
|
||||
uint256 CalcBlockHash() const
|
||||
{
|
||||
CBlockHeader block;
|
||||
block.nVersion = nVersion;
|
||||
|
@ -966,15 +966,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
std::string str = "CDiskBlockIndex(";
|
||||
str += CBlockIndex::ToString();
|
||||
str += strprintf("\n hashBlock=%s, hashPrev=%s)",
|
||||
GetBlockHash().ToString().c_str(),
|
||||
hashPrev.ToString().c_str());
|
||||
return str;
|
||||
}
|
||||
std::string ToString() const; // moved code to main.cpp
|
||||
|
||||
void print() const
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "base58.h"
|
||||
#include "key.h"
|
||||
#include "main.h"
|
||||
#include "auxpow.h"
|
||||
#include "serialize.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
|
||||
#include "main.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
|
56
src/txdb.cpp
56
src/txdb.cpp
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "core.h"
|
||||
#include "uint256.h"
|
||||
#include "auxpow.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -68,9 +69,19 @@ bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, const u
|
|||
CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
|
||||
bool CBlockTreeDB::WriteDiskBlockIndex(const CDiskBlockIndex& diskblockindex)
|
||||
{
|
||||
return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
|
||||
return Write(boost::tuples::make_tuple('b', *diskblockindex.phashBlock, 'a'), diskblockindex);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteBlockIndex(const CBlockIndex& blockindex)
|
||||
{
|
||||
return Write(boost::tuples::make_tuple('b', blockindex.GetBlockHash(), 'b'), blockindex);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReadDiskBlockIndex(const uint256 &blkid, CDiskBlockIndex &diskblockindex)
|
||||
{
|
||||
return Read(boost::tuples::make_tuple('b', blkid, 'a'), diskblockindex);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
|
||||
|
@ -186,7 +197,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
|||
leveldb::Iterator *pcursor = NewIterator();
|
||||
|
||||
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
|
||||
ssKeySet << make_pair('b', uint256(0));
|
||||
ssKeySet << boost::tuples::make_tuple('b', uint256(0), 'a'); // 'b' is the prefix for BlockIndex, 'a' sigifies the first part
|
||||
uint256 hash;
|
||||
char cType;
|
||||
pcursor->Seek(ssKeySet.str());
|
||||
|
||||
// Load mapBlockIndex
|
||||
|
@ -195,32 +208,41 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
|
|||
try {
|
||||
leveldb::Slice slKey = pcursor->key();
|
||||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
char chType;
|
||||
ssKey >> chType;
|
||||
if (chType == 'b') {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CDiskBlockIndex diskindex;
|
||||
ssValue >> diskindex;
|
||||
ssKey >> cType;
|
||||
if (cType == 'b') {
|
||||
ssKey >> hash;
|
||||
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
CDataStream ssValue_immutable(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CDiskBlockIndex diskindex;
|
||||
ssValue_immutable >> diskindex; // read all immutable data
|
||||
|
||||
// Construct immutable parts of block index objecty
|
||||
CBlockIndex* pindexNew = InsertBlockIndex(hash);
|
||||
assert(diskindex.CalcBlockHash() == *pindexNew->phashBlock); // paranoia check
|
||||
|
||||
// Construct block index object
|
||||
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
|
||||
pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
|
||||
pindexNew->nHeight = diskindex.nHeight;
|
||||
pindexNew->nFile = diskindex.nFile;
|
||||
pindexNew->nDataPos = diskindex.nDataPos;
|
||||
pindexNew->nUndoPos = diskindex.nUndoPos;
|
||||
pindexNew->nVersion = diskindex.nVersion;
|
||||
pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
|
||||
pindexNew->nTime = diskindex.nTime;
|
||||
pindexNew->nBits = diskindex.nBits;
|
||||
pindexNew->nNonce = diskindex.nNonce;
|
||||
pindexNew->nStatus = diskindex.nStatus;
|
||||
pindexNew->nTx = diskindex.nTx;
|
||||
|
||||
if (!pindexNew->CheckIndex())
|
||||
// CheckIndex need phashBlock to be set
|
||||
diskindex.phashBlock = pindexNew->phashBlock;
|
||||
if (!diskindex.CheckIndex())
|
||||
return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString());
|
||||
|
||||
pcursor->Next(); // now we should be on the 'b' subkey
|
||||
|
||||
assert(pcursor->Valid());
|
||||
|
||||
slValue = pcursor->value();
|
||||
CDataStream ssValue_mutable(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
ssValue_mutable >> *pindexNew; // read all mutable data
|
||||
|
||||
pcursor->Next();
|
||||
} else {
|
||||
break; // if shutdown requested or finished loading block index
|
||||
|
|
|
@ -51,7 +51,9 @@ private:
|
|||
CBlockTreeDB(const CBlockTreeDB&);
|
||||
void operator=(const CBlockTreeDB&);
|
||||
public:
|
||||
bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
|
||||
bool WriteDiskBlockIndex(const CDiskBlockIndex& diskblockindex);
|
||||
bool WriteBlockIndex(const CBlockIndex& blockindex);
|
||||
bool ReadDiskBlockIndex(const uint256 &blkid, CDiskBlockIndex& diskblockindex);
|
||||
bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork);
|
||||
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
|
||||
bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
|
||||
|
|
Loading…
Reference in a new issue