Merge pull request #3884
942b33a
Split AcceptBlockHeader from AcceptBlock. (Pieter Wuille)f457347
Split up CheckBlock in a block and header version (Pieter Wuille)
This commit is contained in:
commit
d54985f3f1
2 changed files with 179 additions and 72 deletions
206
src/main.cpp
206
src/main.cpp
|
@ -1850,8 +1850,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
||||||
if (fJustCheck)
|
if (fJustCheck)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// Correct transaction counts.
|
||||||
|
pindex->nTx = block.vtx.size();
|
||||||
|
if (pindex->pprev)
|
||||||
|
pindex->nChainTx = pindex->pprev->nChainTx + block.vtx.size();
|
||||||
|
|
||||||
// Write undo information to disk
|
// Write undo information to disk
|
||||||
if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS)
|
if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS))
|
||||||
{
|
{
|
||||||
if (pindex->GetUndoPos().IsNull()) {
|
if (pindex->GetUndoPos().IsNull()) {
|
||||||
CDiskBlockPos pos;
|
CDiskBlockPos pos;
|
||||||
|
@ -1865,7 +1870,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
||||||
pindex->nStatus |= BLOCK_HAVE_UNDO;
|
pindex->nStatus |= BLOCK_HAVE_UNDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS;
|
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);
|
||||||
|
|
||||||
CDiskBlockIndex blockindex(pindex);
|
CDiskBlockIndex blockindex(pindex);
|
||||||
if (!pblocktree->WriteBlockIndex(blockindex))
|
if (!pblocktree->WriteBlockIndex(blockindex))
|
||||||
|
@ -2059,10 +2064,11 @@ void static FindMostWorkChain() {
|
||||||
CBlockIndex *pindexTest = pindexNew;
|
CBlockIndex *pindexTest = pindexNew;
|
||||||
bool fInvalidAncestor = false;
|
bool fInvalidAncestor = false;
|
||||||
while (pindexTest && !chainActive.Contains(pindexTest)) {
|
while (pindexTest && !chainActive.Contains(pindexTest)) {
|
||||||
if (pindexTest->nStatus & BLOCK_FAILED_MASK) {
|
if (!pindexTest->IsValid(BLOCK_VALID_TRANSACTIONS) || !(pindexTest->nStatus & BLOCK_HAVE_DATA)) {
|
||||||
// Candidate has an invalid ancestor, remove entire chain from the set.
|
// Candidate has an invalid ancestor, remove entire chain from the set.
|
||||||
if (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
|
if (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
|
||||||
pindexBestInvalid = pindexNew; CBlockIndex *pindexFailed = pindexNew;
|
pindexBestInvalid = pindexNew;
|
||||||
|
CBlockIndex *pindexFailed = pindexNew;
|
||||||
while (pindexTest != pindexFailed) {
|
while (pindexTest != pindexFailed) {
|
||||||
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
|
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
|
||||||
setBlockIndexValid.erase(pindexFailed);
|
setBlockIndexValid.erase(pindexFailed);
|
||||||
|
@ -2136,12 +2142,14 @@ bool ActivateBestChain(CValidationState &state) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos)
|
|
||||||
|
CBlockIndex* AddToBlockIndex(CBlockHeader& block)
|
||||||
{
|
{
|
||||||
// Check for duplicate
|
// Check for duplicate
|
||||||
uint256 hash = block.GetHash();
|
uint256 hash = block.GetHash();
|
||||||
if (mapBlockIndex.count(hash))
|
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hash);
|
||||||
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString()), 0, "duplicate");
|
if (it != mapBlockIndex.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
// Construct new block index object
|
// Construct new block index object
|
||||||
CBlockIndex* pindexNew = new CBlockIndex(block);
|
CBlockIndex* pindexNew = new CBlockIndex(block);
|
||||||
|
@ -2158,13 +2166,37 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
|
||||||
pindexNew->pprev = (*miPrev).second;
|
pindexNew->pprev = (*miPrev).second;
|
||||||
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
||||||
}
|
}
|
||||||
pindexNew->nTx = block.vtx.size();
|
|
||||||
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256();
|
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256();
|
||||||
pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
|
pindexNew->RaiseValidity(BLOCK_VALID_TREE);
|
||||||
|
|
||||||
|
return pindexNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS).
|
||||||
|
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
|
||||||
|
{
|
||||||
|
pindexNew->nTx = block.vtx.size();
|
||||||
|
if (pindexNew->pprev) {
|
||||||
|
// Not the genesis block.
|
||||||
|
if (pindexNew->pprev->nChainTx) {
|
||||||
|
// This parent's block's total number transactions is known, so compute outs.
|
||||||
|
pindexNew->nChainTx = pindexNew->pprev->nChainTx + pindexNew->nTx;
|
||||||
|
} else {
|
||||||
|
// The total number of transactions isn't known yet.
|
||||||
|
// We will compute it when the block is connected.
|
||||||
|
pindexNew->nChainTx = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Genesis block.
|
||||||
|
pindexNew->nChainTx = pindexNew->nTx;
|
||||||
|
}
|
||||||
pindexNew->nFile = pos.nFile;
|
pindexNew->nFile = pos.nFile;
|
||||||
pindexNew->nDataPos = pos.nPos;
|
pindexNew->nDataPos = pos.nPos;
|
||||||
pindexNew->nUndoPos = 0;
|
pindexNew->nUndoPos = 0;
|
||||||
pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA;
|
pindexNew->nStatus |= BLOCK_HAVE_DATA;
|
||||||
|
|
||||||
|
if (pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS))
|
||||||
setBlockIndexValid.insert(pindexNew);
|
setBlockIndexValid.insert(pindexNew);
|
||||||
|
|
||||||
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
|
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
|
||||||
|
@ -2289,26 +2321,55 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW)
|
||||||
|
{
|
||||||
|
// Check proof of work matches claimed amount
|
||||||
|
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
|
||||||
|
return state.DoS(50, error("CheckBlockHeader() : proof of work failed"),
|
||||||
|
REJECT_INVALID, "high-hash");
|
||||||
|
|
||||||
|
// Check timestamp
|
||||||
|
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
|
||||||
|
return state.Invalid(error("CheckBlockHeader() : block timestamp too far in the future"),
|
||||||
|
REJECT_INVALID, "time-too-new");
|
||||||
|
|
||||||
|
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
|
||||||
|
if (pcheckpoint && block.hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
|
||||||
|
{
|
||||||
|
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
|
||||||
|
int64_t deltaTime = block.GetBlockTime() - pcheckpoint->nTime;
|
||||||
|
if (deltaTime < 0)
|
||||||
|
{
|
||||||
|
return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"),
|
||||||
|
REJECT_CHECKPOINT, "time-too-old");
|
||||||
|
}
|
||||||
|
CBigNum bnNewBlock;
|
||||||
|
bnNewBlock.SetCompact(block.nBits);
|
||||||
|
CBigNum bnRequired;
|
||||||
|
bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
|
||||||
|
if (bnNewBlock > bnRequired)
|
||||||
|
{
|
||||||
|
return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"),
|
||||||
|
REJECT_INVALID, "bad-diffbits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
|
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||||
{
|
{
|
||||||
// These are checks that are independent of context
|
// These are checks that are independent of context
|
||||||
// that can be verified before saving an orphan block.
|
// that can be verified before saving an orphan block.
|
||||||
|
|
||||||
|
if (!CheckBlockHeader(block, state, fCheckPOW))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Size limits
|
// Size limits
|
||||||
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
|
if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
|
||||||
return state.DoS(100, error("CheckBlock() : size limits failed"),
|
return state.DoS(100, error("CheckBlock() : size limits failed"),
|
||||||
REJECT_INVALID, "bad-blk-length");
|
REJECT_INVALID, "bad-blk-length");
|
||||||
|
|
||||||
// Check proof of work matches claimed amount
|
|
||||||
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
|
|
||||||
return state.DoS(50, error("CheckBlock() : proof of work failed"),
|
|
||||||
REJECT_INVALID, "high-hash");
|
|
||||||
|
|
||||||
// Check timestamp
|
|
||||||
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
|
|
||||||
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"),
|
|
||||||
REJECT_INVALID, "time-too-new");
|
|
||||||
|
|
||||||
// First transaction must be coinbase, the rest must not be
|
// First transaction must be coinbase, the rest must not be
|
||||||
if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
|
if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
|
||||||
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"),
|
return state.DoS(100, error("CheckBlock() : first tx is not coinbase"),
|
||||||
|
@ -2355,13 +2416,18 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
// Check for duplicate
|
// Check for duplicate
|
||||||
uint256 hash = block.GetHash();
|
uint256 hash = block.GetHash();
|
||||||
if (mapBlockIndex.count(hash))
|
std::map<uint256, CBlockIndex*>::iterator miSelf = mapBlockIndex.find(hash);
|
||||||
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"), 0, "duplicate");
|
CBlockIndex *pindex = NULL;
|
||||||
|
if (miSelf != mapBlockIndex.end()) {
|
||||||
|
pindex = miSelf->second;
|
||||||
|
if (pindex->nStatus & BLOCK_FAILED_MASK)
|
||||||
|
return state.Invalid(error("AcceptBlock() : block is marked invalid"), 0, "duplicate");
|
||||||
|
}
|
||||||
|
|
||||||
// Get prev block index
|
// Get prev block index
|
||||||
CBlockIndex* pindexPrev = NULL;
|
CBlockIndex* pindexPrev = NULL;
|
||||||
|
@ -2383,12 +2449,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
||||||
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"),
|
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"),
|
||||||
REJECT_INVALID, "time-too-old");
|
REJECT_INVALID, "time-too-old");
|
||||||
|
|
||||||
// Check that all transactions are finalized
|
|
||||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
|
||||||
if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
|
|
||||||
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"),
|
|
||||||
REJECT_INVALID, "bad-txns-nonfinal");
|
|
||||||
|
|
||||||
// Check that the block chain matches the known block chain up to a checkpoint
|
// Check that the block chain matches the known block chain up to a checkpoint
|
||||||
if (!Checkpoints::CheckBlock(nHeight, hash))
|
if (!Checkpoints::CheckBlock(nHeight, hash))
|
||||||
return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight),
|
return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight),
|
||||||
|
@ -2409,16 +2469,55 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
||||||
REJECT_OBSOLETE, "bad-version");
|
REJECT_OBSOLETE, "bad-version");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pindex == NULL)
|
||||||
|
pindex = AddToBlockIndex(block);
|
||||||
|
|
||||||
|
if (ppindex)
|
||||||
|
*ppindex = pindex;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
|
CBlockIndex *&pindex = *ppindex;
|
||||||
|
|
||||||
|
if (!AcceptBlockHeader(block, state, &pindex))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!CheckBlock(block, state)) {
|
||||||
|
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
|
||||||
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
|
if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) {
|
||||||
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
|
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"),
|
||||||
|
REJECT_INVALID, "bad-txns-nonfinal");
|
||||||
|
}
|
||||||
|
|
||||||
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
|
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
|
||||||
if (block.nVersion >= 2)
|
if (block.nVersion >= 2)
|
||||||
{
|
{
|
||||||
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
|
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
|
||||||
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
|
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 750, 1000)) ||
|
||||||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
|
(TestNet() && CBlockIndex::IsSuperMajority(2, pindex->pprev, 51, 100)))
|
||||||
{
|
{
|
||||||
CScript expect = CScript() << nHeight;
|
CScript expect = CScript() << nHeight;
|
||||||
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
|
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
|
||||||
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
|
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
|
||||||
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"),
|
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"),
|
||||||
REJECT_INVALID, "bad-cb-height");
|
REJECT_INVALID, "bad-cb-height");
|
||||||
}
|
}
|
||||||
|
@ -2436,8 +2535,8 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
||||||
if (dbp == NULL)
|
if (dbp == NULL)
|
||||||
if (!WriteBlockToDisk(block, blockPos))
|
if (!WriteBlockToDisk(block, blockPos))
|
||||||
return state.Abort(_("Failed to write block"));
|
return state.Abort(_("Failed to write block"));
|
||||||
if (!AddToBlockIndex(block, state, blockPos))
|
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
|
||||||
return error("AcceptBlock() : AddToBlockIndex failed");
|
return error("AcceptBlock() : ReceivedBlockTransactions failed");
|
||||||
} catch(std::runtime_error &e) {
|
} catch(std::runtime_error &e) {
|
||||||
return state.Abort(_("System error: ") + e.what());
|
return state.Abort(_("System error: ") + e.what());
|
||||||
}
|
}
|
||||||
|
@ -2507,30 +2606,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
||||||
if (!CheckBlock(*pblock, state))
|
if (!CheckBlock(*pblock, state))
|
||||||
return error("ProcessBlock() : CheckBlock FAILED");
|
return error("ProcessBlock() : CheckBlock FAILED");
|
||||||
|
|
||||||
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
|
// If we don't already have its previous block (with full data), shunt it off to holding area until we get it
|
||||||
if (pcheckpoint && pblock->hashPrevBlock != (chainActive.Tip() ? chainActive.Tip()->GetBlockHash() : uint256(0)))
|
std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pblock->hashPrevBlock);
|
||||||
{
|
if (pblock->hashPrevBlock != 0 && (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)))
|
||||||
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
|
|
||||||
int64_t deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
|
|
||||||
if (deltaTime < 0)
|
|
||||||
{
|
|
||||||
return state.DoS(100, error("ProcessBlock() : block with timestamp before last checkpoint"),
|
|
||||||
REJECT_CHECKPOINT, "time-too-old");
|
|
||||||
}
|
|
||||||
CBigNum bnNewBlock;
|
|
||||||
bnNewBlock.SetCompact(pblock->nBits);
|
|
||||||
CBigNum bnRequired;
|
|
||||||
bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
|
|
||||||
if (bnNewBlock > bnRequired)
|
|
||||||
{
|
|
||||||
return state.DoS(100, error("ProcessBlock() : block with too little proof-of-work"),
|
|
||||||
REJECT_INVALID, "bad-diffbits");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// If we don't already have its previous block, shunt it off to holding area until we get it
|
|
||||||
if (pblock->hashPrevBlock != 0 && !mapBlockIndex.count(pblock->hashPrevBlock))
|
|
||||||
{
|
{
|
||||||
LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString());
|
LogPrintf("ProcessBlock: ORPHAN BLOCK %lu, prev=%s\n", (unsigned long)mapOrphanBlocks.size(), pblock->hashPrevBlock.ToString());
|
||||||
|
|
||||||
|
@ -2555,7 +2633,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store to disk
|
// Store to disk
|
||||||
if (!AcceptBlock(*pblock, state, dbp))
|
CBlockIndex *pindex = NULL;
|
||||||
|
bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
|
||||||
|
if (!ret)
|
||||||
return error("ProcessBlock() : AcceptBlock FAILED");
|
return error("ProcessBlock() : AcceptBlock FAILED");
|
||||||
|
|
||||||
// Recursively process any orphan blocks that depended on this one
|
// Recursively process any orphan blocks that depended on this one
|
||||||
|
@ -2576,7 +2656,8 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
||||||
block.BuildMerkleTree();
|
block.BuildMerkleTree();
|
||||||
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
|
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
|
||||||
CValidationState stateDummy;
|
CValidationState stateDummy;
|
||||||
if (AcceptBlock(block, stateDummy))
|
CBlockIndex *pindexChild = NULL;
|
||||||
|
if (AcceptBlock(block, stateDummy, &pindexChild))
|
||||||
vWorkQueue.push_back(mi->second->hashBlock);
|
vWorkQueue.push_back(mi->second->hashBlock);
|
||||||
mapOrphanBlocks.erase(mi->second->hashBlock);
|
mapOrphanBlocks.erase(mi->second->hashBlock);
|
||||||
delete mi->second;
|
delete mi->second;
|
||||||
|
@ -2839,7 +2920,7 @@ bool static LoadBlockIndexDB()
|
||||||
CBlockIndex* pindex = item.second;
|
CBlockIndex* pindex = item.second;
|
||||||
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork().getuint256();
|
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + pindex->GetBlockWork().getuint256();
|
||||||
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
|
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
|
||||||
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK))
|
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS))
|
||||||
setBlockIndexValid.insert(pindex);
|
setBlockIndexValid.insert(pindex);
|
||||||
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
|
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
|
||||||
pindexBestInvalid = pindex;
|
pindexBestInvalid = pindex;
|
||||||
|
@ -2987,7 +3068,8 @@ bool InitBlockIndex() {
|
||||||
return error("LoadBlockIndex() : FindBlockPos failed");
|
return error("LoadBlockIndex() : FindBlockPos failed");
|
||||||
if (!WriteBlockToDisk(block, blockPos))
|
if (!WriteBlockToDisk(block, blockPos))
|
||||||
return error("LoadBlockIndex() : writing genesis block to disk failed");
|
return error("LoadBlockIndex() : writing genesis block to disk failed");
|
||||||
if (!AddToBlockIndex(block, state, blockPos))
|
CBlockIndex *pindex = AddToBlockIndex(block);
|
||||||
|
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
|
||||||
return error("LoadBlockIndex() : genesis block not accepted");
|
return error("LoadBlockIndex() : genesis block not accepted");
|
||||||
} catch(std::runtime_error &e) {
|
} catch(std::runtime_error &e) {
|
||||||
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
|
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
|
||||||
|
|
27
src/main.h
27
src/main.h
|
@ -603,11 +603,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
|
||||||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
||||||
|
|
||||||
// Context-independent validity checks
|
// 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 CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
// Store block on disk
|
// Store block on disk
|
||||||
// if dbp is provided, the file is known to already reside on disk
|
// if dbp is provided, the file is known to already reside on disk
|
||||||
bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL);
|
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
|
||||||
|
bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -865,6 +867,29 @@ public:
|
||||||
{
|
{
|
||||||
LogPrintf("%s\n", ToString().c_str());
|
LogPrintf("%s\n", ToString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether this block index entry is valid up to the passed validity level.
|
||||||
|
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
|
||||||
|
{
|
||||||
|
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
|
||||||
|
if (nStatus & BLOCK_FAILED_MASK)
|
||||||
|
return false;
|
||||||
|
return ((nStatus & BLOCK_VALID_MASK) >= nUpTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise the validity level of this block index entry.
|
||||||
|
// Returns true if the validity was changed.
|
||||||
|
bool RaiseValidity(enum BlockStatus nUpTo)
|
||||||
|
{
|
||||||
|
assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed.
|
||||||
|
if (nStatus & BLOCK_FAILED_MASK)
|
||||||
|
return false;
|
||||||
|
if ((nStatus & BLOCK_VALID_MASK) < nUpTo) {
|
||||||
|
nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue