Block height in coinbase as a new block rule

"Version 2" blocks are blocks that have nVersion=2 and
have the block height as the first item in their coinbase.
Block-height-in-the-coinbase is strictly enforced when
version=2 blocks are a supermajority in the block chain
(750 of the last 1,000 blocks on main net, 51 of 100 for
testnet). This does not affect old clients/miners at all,
which will continue producing nVersion=1 blocks, and
which will continue to be valid.
This commit is contained in:
Gavin Andresen 2012-06-27 19:30:39 -04:00
parent 3fcec0d4a0
commit de237cbfa4
2 changed files with 34 additions and 2 deletions

View file

@ -1826,6 +1826,19 @@ bool CBlock::AcceptBlock()
if (!Checkpoints::CheckBlock(nHeight, hash)) if (!Checkpoints::CheckBlock(nHeight, hash))
return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); return DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
if (nVersion > 1)
{
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
if ((!fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
(fTestNet && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
{
CScript expect = CScript() << nHeight;
if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
return DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
}
}
// Write block to history file // Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION))) if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
return error("AcceptBlock() : out of disk space"); return error("AcceptBlock() : out of disk space");
@ -1849,6 +1862,18 @@ bool CBlock::AcceptBlock()
return true; return true;
} }
bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
{
unsigned int nFound = 0;
for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++)
{
if (pstart->nVersion >= minVersion)
++nFound;
pstart = pstart->pprev;
}
return (nFound >= nRequired);
}
bool ProcessBlock(CNode* pfrom, CBlock* pblock) bool ProcessBlock(CNode* pfrom, CBlock* pblock)
{ {
// Check for duplicate // Check for duplicate
@ -3663,7 +3688,8 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
hashPrevBlock = pblock->hashPrevBlock; hashPrevBlock = pblock->hashPrevBlock;
} }
++nExtraNonce; ++nExtraNonce;
pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100); assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->hashMerkleRoot = pblock->BuildMerkleTree();

View file

@ -820,7 +820,7 @@ class CBlock
{ {
public: public:
// header // header
static const int CURRENT_VERSION=1; static const int CURRENT_VERSION=2;
int nVersion; int nVersion;
uint256 hashPrevBlock; uint256 hashPrevBlock;
uint256 hashMerkleRoot; uint256 hashMerkleRoot;
@ -1164,6 +1164,12 @@ public:
return pindex->GetMedianTimePast(); return pindex->GetMedianTimePast();
} }
/**
* Returns true if there are nRequired or more blocks of minVersion or above
* in the last nToCheck blocks, starting at pstart and going backwards.
*/
static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart,
unsigned int nRequired, unsigned int nToCheck);
std::string ToString() const std::string ToString() const