|
|
|
@ -2334,6 +2334,73 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
@@ -2334,6 +2334,73 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) |
|
|
|
|
{ |
|
|
|
|
uint256 hash = block.GetHash(); |
|
|
|
|
if (hash == Params().HashGenesisBlock()) |
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
assert(pindexPrev); |
|
|
|
|
|
|
|
|
|
int nHeight = pindexPrev->nHeight+1; |
|
|
|
|
|
|
|
|
|
// Check proof of work
|
|
|
|
|
if ((!Params().SkipProofOfWorkCheck()) && |
|
|
|
|
(block.nBits != GetNextWorkRequired(pindexPrev, &block))) |
|
|
|
|
return state.DoS(100, error("%s : incorrect proof of work", __func__), |
|
|
|
|
REJECT_INVALID, "bad-diffbits"); |
|
|
|
|
|
|
|
|
|
// Check timestamp against prev
|
|
|
|
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) |
|
|
|
|
return state.Invalid(error("%s : block's timestamp is too early", __func__), |
|
|
|
|
REJECT_INVALID, "time-too-old"); |
|
|
|
|
|
|
|
|
|
// Check that the block chain matches the known block chain up to a checkpoint
|
|
|
|
|
if (!Checkpoints::CheckBlock(nHeight, hash)) |
|
|
|
|
return state.DoS(100, error("%s : rejected by checkpoint lock-in at %d", __func__, nHeight), |
|
|
|
|
REJECT_CHECKPOINT, "checkpoint mismatch"); |
|
|
|
|
|
|
|
|
|
// Don't accept any forks from the main chain prior to last checkpoint
|
|
|
|
|
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); |
|
|
|
|
if (pcheckpoint && nHeight < pcheckpoint->nHeight) |
|
|
|
|
return state.DoS(100, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); |
|
|
|
|
|
|
|
|
|
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
|
|
|
|
|
if (block.nVersion < 2 && |
|
|
|
|
CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) |
|
|
|
|
{ |
|
|
|
|
return state.Invalid(error("%s : rejected nVersion=1 block", __func__), |
|
|
|
|
REJECT_OBSOLETE, "bad-version"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) |
|
|
|
|
{ |
|
|
|
|
const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; |
|
|
|
|
|
|
|
|
|
// Check that all transactions are finalized
|
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) |
|
|
|
|
if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { |
|
|
|
|
return state.DoS(10, error("%s : contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
|
|
|
|
|
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
|
|
|
|
|
if (block.nVersion >= 2 && |
|
|
|
|
CBlockIndex::IsSuperMajority(2, pindexPrev, Params().EnforceBlockUpgradeMajority())) |
|
|
|
|
{ |
|
|
|
|
CScript expect = CScript() << nHeight; |
|
|
|
|
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || |
|
|
|
|
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { |
|
|
|
|
return state.DoS(100, error("%s : block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) |
|
|
|
|
{ |
|
|
|
|
AssertLockHeld(cs_main); |
|
|
|
@ -2353,44 +2420,16 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
@@ -2353,44 +2420,16 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
|
|
|
|
|
|
|
|
|
|
// Get prev block index
|
|
|
|
|
CBlockIndex* pindexPrev = NULL; |
|
|
|
|
int nHeight = 0; |
|
|
|
|
if (hash != Params().HashGenesisBlock()) { |
|
|
|
|
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); |
|
|
|
|
if (mi == mapBlockIndex.end()) |
|
|
|
|
return state.DoS(10, error("%s : prev block not found", __func__), 0, "bad-prevblk"); |
|
|
|
|
pindexPrev = (*mi).second; |
|
|
|
|
nHeight = pindexPrev->nHeight+1; |
|
|
|
|
|
|
|
|
|
// Check proof of work
|
|
|
|
|
if ((!Params().SkipProofOfWorkCheck()) && |
|
|
|
|
(block.nBits != GetNextWorkRequired(pindexPrev, &block))) |
|
|
|
|
return state.DoS(100, error("%s : incorrect proof of work", __func__), |
|
|
|
|
REJECT_INVALID, "bad-diffbits"); |
|
|
|
|
|
|
|
|
|
// Check timestamp against prev
|
|
|
|
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) |
|
|
|
|
return state.Invalid(error("%s : block's timestamp is too early", __func__), |
|
|
|
|
REJECT_INVALID, "time-too-old"); |
|
|
|
|
|
|
|
|
|
// Check that the block chain matches the known block chain up to a checkpoint
|
|
|
|
|
if (!Checkpoints::CheckBlock(nHeight, hash)) |
|
|
|
|
return state.DoS(100, error("%s : rejected by checkpoint lock-in at %d", __func__, nHeight), |
|
|
|
|
REJECT_CHECKPOINT, "checkpoint mismatch"); |
|
|
|
|
|
|
|
|
|
// Don't accept any forks from the main chain prior to last checkpoint
|
|
|
|
|
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); |
|
|
|
|
if (pcheckpoint && nHeight < pcheckpoint->nHeight) |
|
|
|
|
return state.DoS(100, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); |
|
|
|
|
|
|
|
|
|
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
|
|
|
|
|
if (block.nVersion < 2 && |
|
|
|
|
CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) |
|
|
|
|
{ |
|
|
|
|
return state.Invalid(error("%s : rejected nVersion=1 block", __func__), |
|
|
|
|
REJECT_OBSOLETE, "bad-version"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!ContextualCheckBlockHeader(block, state, pindexPrev)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
if (pindex == NULL) |
|
|
|
|
pindex = AddToBlockIndex(block); |
|
|
|
|
|
|
|
|
@ -2415,7 +2454,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
@@ -2415,7 +2454,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!CheckBlock(block, state)) { |
|
|
|
|
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { |
|
|
|
|
if (state.IsInvalid() && !state.CorruptionPossible()) { |
|
|
|
|
pindex->nStatus |= BLOCK_FAILED_VALID; |
|
|
|
|
} |
|
|
|
@ -2424,27 +2463,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
@@ -2424,27 +2463,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
|
|
|
|
|
|
|
|
|
int nHeight = pindex->nHeight; |
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
|
|
|
|
|
if (block.nVersion >= 2 && |
|
|
|
|
CBlockIndex::IsSuperMajority(2, pindex->pprev, Params().EnforceBlockUpgradeMajority())) |
|
|
|
|
{ |
|
|
|
|
CScript expect = CScript() << nHeight; |
|
|
|
|
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || |
|
|
|
|
!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"), REJECT_INVALID, "bad-cb-height"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Write block to history file
|
|
|
|
|
try { |
|
|
|
|
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); |
|
|
|
|