Merge pull request #584 from patricklodder/1.8-dev-auxpow

Enable auxpow for Dogecoin
This commit is contained in:
langerhans 2014-08-03 23:43:37 +02:00
commit 98b93577d2
17 changed files with 796 additions and 79 deletions

View file

@ -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 \

132
src/auxpow.cpp Normal file
View file

@ -0,0 +1,132 @@
// Copyright (c) 2011 Vince Durham
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "script.h"
#include "auxpow.h"
#include "init.h"
using namespace std;
using namespace boost;
unsigned char pchMergedMiningHeader[] = { 0xfa, 0xbe, 'm', 'm' } ;
void RemoveMergedMiningHeader(vector<unsigned char>& vchAux)
{
if (vchAux.begin() != std::search(vchAux.begin(), vchAux.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)))
throw runtime_error("merged mining aux too short");
vchAux.erase(vchAux.begin(), vchAux.begin() + sizeof(pchMergedMiningHeader));
}
bool CAuxPow::Check(uint256 hashAuxBlock, int nChainID)
{
if (nIndex != 0)
return error("AuxPow is not a generate");
if (!TestNet() && parentBlockHeader.GetChainID() == nChainID)
return error("Aux POW parent has our chain ID");
if (vChainMerkleBranch.size() > 30)
return error("Aux POW chain merkle branch too long");
// Check that the chain merkle root is in the coinbase
uint256 nRootHash = CBlock::CheckMerkleBranch(hashAuxBlock, vChainMerkleBranch, nChainIndex);
vector<unsigned char> vchRootHash(nRootHash.begin(), nRootHash.end());
std::reverse(vchRootHash.begin(), vchRootHash.end()); // correct endian
// Check that we are in the parent block merkle tree
if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != parentBlockHeader.hashMerkleRoot)
return error("Aux POW merkle root incorrect");
const CScript script = vin[0].scriptSig;
// Check that the same work is not submitted twice to our chain.
//
CScript::const_iterator pcHead =
std::search(script.begin(), script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
CScript::const_iterator pc =
std::search(script.begin(), script.end(), vchRootHash.begin(), vchRootHash.end());
if (pcHead == script.end())
return error("MergedMiningHeader missing from parent coinbase");
if (pc == script.end())
return error("Aux POW missing chain merkle root in parent coinbase");
if (pcHead != script.end())
{
// Enforce only one chain merkle root by checking that a single instance of the merged
// mining header exists just before.
if (script.end() != std::search(pcHead + 1, script.end(), UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader)))
return error("Multiple merged mining headers in coinbase");
if (pcHead + sizeof(pchMergedMiningHeader) != pc)
return error("Merged mining header is not just before chain merkle root");
}
else
{
// For backward compatibility.
// Enforce only one chain merkle root by checking that it starts early in the coinbase.
// 8-12 bytes are enough to encode extraNonce and nBits.
if (pc - script.begin() > 20)
return error("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase");
}
// Ensure we are at a deterministic point in the merkle leaves by hashing
// a nonce and our chain ID and comparing to the index.
pc += vchRootHash.size();
if (script.end() - pc < 8)
return error("Aux POW missing chain merkle tree size and nonce in parent coinbase");
int nSize;
memcpy(&nSize, &pc[0], 4);
if (nSize != (1 << vChainMerkleBranch.size()))
return error("Aux POW merkle branch size does not match parent coinbase");
int nNonce;
memcpy(&nNonce, &pc[4], 4);
// Choose a pseudo-random slot in the chain merkle tree
// but have it be fixed for a size/nonce/chain combination.
//
// This prevents the same work from being used twice for the
// same chain while reducing the chance that two chains clash
// for the same slot.
unsigned int rand = nNonce;
rand = rand * 1103515245 + 12345;
rand += nChainID;
rand = rand * 1103515245 + 12345;
if (nChainIndex != (rand % nSize))
return error("Aux POW wrong index");
return true;
}
CScript MakeCoinbaseWithAux(unsigned int nBits, unsigned int nExtraNonce, vector<unsigned char>& vchAux)
{
vector<unsigned char> vchAuxWithHeader(UBEGIN(pchMergedMiningHeader), UEND(pchMergedMiningHeader));
vchAuxWithHeader.insert(vchAuxWithHeader.end(), vchAux.begin(), vchAux.end());
// Push OP_2 just in case we want versioning later
return CScript() << nBits << nExtraNonce << OP_2 << vchAuxWithHeader;
}
void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, vector<unsigned char>& vchAux)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock)
{
nExtraNonce = 0;
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(pblock->nBits, nExtraNonce, vchAux);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}

84
src/auxpow.h Normal file
View file

@ -0,0 +1,84 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_AUXPOW_H
#define BITCOIN_AUXPOW_H
#include "main.h"
class CAuxPow : public CMerkleTx
{
public:
CAuxPow(const CTransaction& txIn) : CMerkleTx(txIn)
{
}
CAuxPow() :CMerkleTx()
{
}
// Merkle branch with root vchAux
// root must be present inside the coinbase
std::vector<uint256> vChainMerkleBranch;
// Index of chain in chains merkle tree
unsigned int nChainIndex;
CBlockHeader parentBlockHeader;
IMPLEMENT_SERIALIZE
(
nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);
nVersion = this->nVersion;
READWRITE(vChainMerkleBranch);
READWRITE(nChainIndex);
// Always serialize the saved parent block as header so that the size of CAuxPow
// is consistent.
nSerSize += SerReadWrite(s, parentBlockHeader, nType, nVersion, ser_action);
)
bool Check(uint256 hashAuxBlock, int nChainID);
uint256 GetParentBlockHash()
{
return parentBlockHeader.GetPoWHash();
}
};
template <typename Stream>
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionGetSerializeSize ser_action)
{
if (nVersion & BLOCK_VERSION_AUXPOW)
{
return ::GetSerializeSize(*auxpow, nType, nVersion);
}
return 0;
}
template <typename Stream>
int ReadWriteAuxPow(Stream& s, const boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionSerialize ser_action)
{
if (nVersion & BLOCK_VERSION_AUXPOW)
{
return SerReadWrite(s, *auxpow, nType, nVersion, ser_action);
}
return 0;
}
template <typename Stream>
int ReadWriteAuxPow(Stream& s, boost::shared_ptr<CAuxPow>& auxpow, int nType, int nVersion, CSerActionUnserialize ser_action)
{
if (nVersion & BLOCK_VERSION_AUXPOW)
{
auxpow.reset(new CAuxPow());
return SerReadWrite(s, *auxpow, nType, nVersion, ser_action);
}
else
{
auxpow.reset();
return 0;
}
}
extern void RemoveMergedMiningHeader(std::vector<unsigned char>& vchAux);
extern CScript MakeCoinbaseWithAux(unsigned int nBits, unsigned int nExtraNonce, std::vector<unsigned char>& vchAux);
#endif

View file

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "core.h"
#include "auxpow.h"
#include "util.h"

View file

@ -17,6 +17,27 @@
#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);
// primary version
static const int BLOCK_VERSION_DEFAULT = (1 << 0);
static const int BLOCK_VERSION_AUXPOW = (1 << 8);
static const int BLOCK_VERSION_CHAIN_START = (1 << 16);
static const int BLOCK_VERSION_CHAIN_END = (1 << 30);
// DogeCoin aux chain ID = 0x0062 (98)
static const int AUXPOW_CHAIN_ID = 0x0062;
static const int AUXPOW_START_MAINNET = INT_MAX; //TODO change me
static const int AUXPOW_START_TESTNET = 158100;
/** 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
@ -350,6 +371,7 @@ public:
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
boost::shared_ptr<CAuxPow> auxpow;
CBlockHeader()
{
@ -365,11 +387,20 @@ public:
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
nSerSize += ReadWriteAuxPow(s, auxpow, nType, nVersion, ser_action);
)
int GetChainID() const
{
return nVersion / BLOCK_VERSION_CHAIN_START;
}
void SetAuxPow(CAuxPow* pow);
void SetNull()
{
nVersion = CBlockHeader::CURRENT_VERSION;
nVersion = CBlockHeader::CURRENT_VERSION | (AUXPOW_CHAIN_ID * BLOCK_VERSION_CHAIN_START);
hashPrevBlock = 0;
hashMerkleRoot = 0;
nTime = 0;
@ -395,6 +426,8 @@ public:
{
return (int64_t)nTime;
}
bool CheckProofOfWork(int nHeight) const;
};

View file

@ -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"));
}
@ -2050,7 +2059,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
const CBlockIndex* pindex = chainActive.Tip();
for (int i = 0; i < 100 && pindex != NULL; i++)
{
if (pindex->nVersion > CBlock::CURRENT_VERSION)
if (pindex->nVersion > CBlock::CURRENT_VERSION && pindex->nVersion != BLOCK_VERSION_AUXPOW)
++nUpgraded;
pindex = pindex->pprev;
}
@ -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 AUXPOW_START_TESTNET;
else
return AUXPOW_START_MAINNET;
}
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() != AUXPOW_CHAIN_ID)
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) {

View file

@ -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
{

View file

@ -12,6 +12,7 @@
#include "main.h"
#include "net.h"
#include "scrypt.h"
#include "auxpow.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
@ -472,12 +473,30 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
uint256 hash = pblock->GetPoWHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
if (hash > hashTarget)
return false;
CAuxPow *auxpow = pblock->auxpow.get();
//// debug print
LogPrintf("DogecoinMiner:\n");
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
if (auxpow != NULL) {
if (!auxpow->Check(pblock->GetHash(), pblock->GetChainID()))
return error("AUX POW is not valid");
if (auxpow->GetParentBlockHash() > hashTarget)
return error("AUX POW parent hash %s is not under target %s", auxpow->GetParentBlockHash().GetHex().c_str(), hashTarget.GetHex().c_str());
// print to log
LogPrintf("DogecoinMiner: AUX proof-of-work found; our hash: %s ; parent hash: %s ; target: %s\n",
hash.GetHex().c_str(),
auxpow->GetParentBlockHash().GetHex().c_str(),
hashTarget.GetHex().c_str());
}
else
{
if (hash > hashTarget)
return false;
// print to log
LogPrintf("DogecoinMiner: proof-of-work found; hash: %s ; target: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
}
pblock->print();
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());

View file

@ -7,6 +7,7 @@
#define BITCOIN_MINER_H
#include <stdint.h>
#include <vector>
class CBlock;
class CBlockIndex;
@ -14,6 +15,7 @@ struct CBlockTemplate;
class CReserveKey;
class CScript;
class CWallet;
class CAuxPow;
/** Run the miner threads */
void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
@ -22,6 +24,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
/** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void IncrementExtraNonceWithAux(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, std::vector<unsigned char>& vchAux);
/** Do mining precalculation */
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
/** Check mined block */

View file

@ -7,6 +7,7 @@
#include "main.h"
#include "sync.h"
#include "checkpoints.h"
#include "auxpow.h"
#include <stdint.h>
@ -15,6 +16,9 @@
using namespace json_spirit;
using namespace std;
// from rpcraw.cpp
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
double GetDifficulty(const CBlockIndex* blockindex)
@ -60,6 +64,38 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
if (block.nVersion & BLOCK_VERSION_AUXPOW) {
// this block includes auxpow
Object auxpow;
auxpow.push_back(Pair("size", (int)::GetSerializeSize(*block.auxpow, SER_NETWORK, PROTOCOL_VERSION)));
Object coinbasetx;
TxToJSON(*block.auxpow, 0, coinbasetx);
auxpow.push_back(Pair("coinbasetx", Value(coinbasetx)));
Array coinbaseMerkle;
BOOST_FOREACH(const uint256 &hash, block.auxpow->vMerkleBranch)
coinbaseMerkle.push_back(hash.GetHex());
auxpow.push_back(Pair("coinbaseMerkleBranch", coinbaseMerkle));
auxpow.push_back(Pair("coinbaseIndex", block.auxpow->nIndex));
Array chainMerkle;
BOOST_FOREACH(const uint256 &hash, block.auxpow->vChainMerkleBranch)
chainMerkle.push_back(hash.GetHex());
auxpow.push_back(Pair("chainMerkleBranch", chainMerkle));
auxpow.push_back(Pair("chainIndex", (boost::uint64_t)block.auxpow->nChainIndex));
Object parent_block;
parent_block.push_back(Pair("hash", block.auxpow->parentBlockHeader.GetHash().GetHex()));
parent_block.push_back(Pair("version", (boost::uint64_t)block.auxpow->parentBlockHeader.nVersion));
parent_block.push_back(Pair("previousblockhash", block.auxpow->parentBlockHeader.hashPrevBlock.GetHex()));
parent_block.push_back(Pair("merkleroot", block.auxpow->parentBlockHeader.hashMerkleRoot.GetHex()));
parent_block.push_back(Pair("time", (boost::int64_t)block.auxpow->parentBlockHeader.nTime));
parent_block.push_back(Pair("bits", HexBits(block.auxpow->parentBlockHeader.nBits)));
parent_block.push_back(Pair("nonce", (boost::uint64_t)block.auxpow->parentBlockHeader.nNonce));
auxpow.push_back(Pair("parent_block", Value(parent_block)));
result.push_back(Pair("auxpow", Value(auxpow)));
}
Array txs;
BOOST_FOREACH(const CTransaction&tx, block.vtx)
txs.push_back(tx.GetHash().GetHex());

View file

@ -5,6 +5,7 @@
#include "rpcserver.h"
#include "chainparams.h"
#include "auxpow.h"
#include "init.h"
#include "net.h"
#include "main.h"
@ -629,3 +630,278 @@ Value submitblock(const Array& params, bool fHelp)
return Value::null;
}
#ifdef ENABLE_WALLET
Value getworkaux(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1)
throw runtime_error(
"getworkaux <aux>\n"
"getworkaux '' <data>\n"
"getworkaux 'submit' <data>\n"
"getworkaux '' <data> <chain-index> <branch>*\n"
" get work with auxiliary data in coinbase, for multichain mining\n"
"<aux> is the merkle root of the auxiliary chain block hashes, concatenated with the aux chain merkle tree size and a nonce\n"
"<chain-index> is the aux chain index in the aux chain merkle tree\n"
"<branch> is the optional merkle branch of the aux chain\n"
"If <data> is not specified, returns formatted hash data to work on:\n"
" \"midstate\" : precomputed hash state after hashing the first half of the data\n"
" \"data\" : block data\n"
" \"hash1\" : formatted hash buffer for second hash\n"
" \"target\" : little endian hash target\n"
"If <data> is specified and 'submit', tries to solve the block for this (parent) chain and returns true if it was successful."
"If <data> is specified and empty first argument, returns the aux merkle root, with size and nonce."
"If <data> and <chain-index> are specified, creates an auxiliary proof of work for the chain specified and returns:\n"
" \"aux\" : merkle root of auxiliary chain block hashes\n"
" \"auxpow\" : aux proof of work to submit to aux chain\n"
);
if (vNodes.empty())
throw JSONRPCError(-9, "Dogecoin is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "Dogecoin is downloading blocks...");
static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
static vector<CBlockTemplate*> vNewBlockTemplate;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 1)
{
static vector<unsigned char> vchAuxPrev;
vector<unsigned char> vchAux = ParseHex(params[0].get_str());
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
static uint64_t nStart;
static CBlockTemplate* pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
if (pindexPrev != chainActive.Tip())
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
delete pblocktemplate;
vNewBlockTemplate.clear();
}
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
pindexPrev = chainActive.Tip();
vchAuxPrev = vchAux;
nStart = GetTime();
// Create new block
pblocktemplate = CreateNewBlockWithKey(*pMiningKey);
if (!pblocktemplate)
throw JSONRPCError(-7, "Out of memory");
vNewBlockTemplate.push_back(pblocktemplate);
}
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
pblock->nNonce = 0;
// Update nExtraNonce
static unsigned int nExtraNonce = 0;
IncrementExtraNonceWithAux(pblock, pindexPrev, nExtraNonce, vchAux);
// Save
mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
// Prebuild hash buffers
char pmidstate[32];
char pdata[128];
char phash1[64];
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
return result;
}
else
{
if (params[0].get_str() != "submit" && params[0].get_str() != "")
throw JSONRPCError(-8, "<aux> must be the empty string or 'submit' if work is being submitted");
// Parse parameters
vector<unsigned char> vchData = ParseHex(params[1].get_str());
if (vchData.size() != 128)
throw JSONRPCError(-8, "Invalid parameter");
CBlock* pdata = (CBlock*)&vchData[0];
// Byte reverse
for (int i = 0; i < 128/4; i++)
((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
return false;
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
pblock->nTime = pdata->nTime;
pblock->nNonce = pdata->nNonce;
// Get the aux merkle root from the coinbase
CScript script = pblock->vtx[0].vin[0].scriptSig;
opcodetype opcode;
CScript::const_iterator pc = script.begin();
script.GetOp(pc, opcode);
script.GetOp(pc, opcode);
script.GetOp(pc, opcode);
if (opcode != OP_2)
throw runtime_error("invalid aux pow script");
vector<unsigned char> vchAux;
script.GetOp(pc, opcode, vchAux);
RemoveMergedMiningHeader(vchAux);
pblock->vtx[0].vin[0].scriptSig = MakeCoinbaseWithAux(pblock->nBits, nExtraNonce, vchAux);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
if (params.size() > 2)
{
// Requested aux proof of work
int nChainIndex = params[2].get_int();
CAuxPow pow(pblock->vtx[0]);
for (unsigned int i = 3 ; i < params.size() ; i++)
{
uint256 nHash;
nHash.SetHex(params[i].get_str());
pow.vChainMerkleBranch.push_back(nHash);
}
pow.SetMerkleBranch(pblock);
pow.nChainIndex = nChainIndex;
pow.parentBlockHeader = *pblock;
CDataStream ss(SER_GETHASH, PROTOCOL_VERSION);
ss << pow;
Object result;
result.push_back(Pair("auxpow", HexStr(ss.begin(), ss.end())));
return result;
}
else
{
if (params[0].get_str() == "submit")
{
return CheckWork(pblock, *pwalletMain, reservekey);
}
else
{
Object result;
result.push_back(Pair("aux", HexStr(vchAux.begin(), vchAux.end())));
result.push_back(Pair("hash", pblock->GetHash().GetHex()));
return result;
}
}
}
}
Value getauxblock(const Array& params, bool fHelp)
{
if (fHelp || (params.size() != 0 && params.size() != 2))
throw runtime_error(
"getauxblock [<hash> <auxpow>]\n"
" create a new block"
"If <hash>, <auxpow> is not specified, returns a new block hash.\n"
"If <hash>, <auxpow> is specified, tries to solve the block based on "
"the aux proof of work and returns true if it was successful.");
if (vNodes.empty())
throw JSONRPCError(-9, "Dogecoin is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "Dogecoin is downloading blocks...");
static map<uint256, CBlock*> mapNewBlock;
static vector<CBlockTemplate*> vNewBlockTemplate;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
{
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
static uint64_t nStart;
static CBlock* pblock;
static CBlockTemplate* pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
if (pindexPrev != chainActive.Tip())
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate)
delete pblocktemplate;
vNewBlockTemplate.clear();
}
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
pindexPrev = chainActive.Tip();
nStart = GetTime();
// Create new block with nonce = 0 and extraNonce = 1
pblocktemplate = CreateNewBlockWithKey(*pMiningKey);
if (!pblocktemplate)
throw JSONRPCError(-7, "Out of memory");
pblock = &pblocktemplate->block;
// Update nTime
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
pblock->nNonce = 0;
// Push OP_2 just in case we want versioning later
pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CScriptNum(1) << OP_2;
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
// Sets the version
pblock->SetAuxPow(new CAuxPow());
// Save
mapNewBlock[pblock->GetHash()] = pblock;
vNewBlockTemplate.push_back(pblocktemplate);
}
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
Object result;
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
result.push_back(Pair("hash", pblock->GetHash().GetHex()));
result.push_back(Pair("chainid", pblock->GetChainID()));
return result;
}
else
{
uint256 hash;
hash.SetHex(params[0].get_str());
vector<unsigned char> vchAuxPow = ParseHex(params[1].get_str());
CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
CAuxPow* pow = new CAuxPow();
ss >> *pow;
if (!mapNewBlock.count(hash))
return ::error("getauxblock() : block not found");
CBlock* pblock = mapNewBlock[hash];
pblock->SetAuxPow(pow);
if (!CheckWork(pblock, *pwalletMain, reservekey))
{
return false;
}
else
{
return true;
}
}
}
#endif

View file

@ -317,6 +317,9 @@ static const CRPCCommand vRPCCommands[] =
{ "gethashespersec", &gethashespersec, true, false, false },
{ "getwork", &getwork, true, false, true },
{ "setgenerate", &setgenerate, true, true, false },
{ "getwork", &getwork, true, false, true },
{ "getworkaux", &getworkaux, true, false, true },
{ "getauxblock", &getauxblock, true, false, true }
#endif // ENABLE_WALLET
};

View file

@ -134,6 +134,9 @@ extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getworkaux(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getauxblock(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp);

View file

@ -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"

View file

@ -9,6 +9,7 @@
#include "main.h"
#include "auxpow.h"
#include <cstdio>

View file

@ -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

View file

@ -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);