Mercurial > hg > bitcoin
changeset 3192:7b15a490bb10 draft
CreateNewBlock: Check that the produced CBlock is acceptable (except for proof-of-work and merkletree, since those need to be provided later)
This throws an exception from CreateNewBlock otherwise, which is not safe without #1245!
author | Luke Dashjr <luke-jr+git@utopios.org> |
---|---|
date | Wed, 09 May 2012 17:24:44 +0000 |
parents | 6af3ffcb33e8 |
children | 6d470300b634 |
files | src/main.cpp src/main.h |
diffstat | 2 files changed, 33 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main.cpp +++ b/src/main.cpp @@ -1252,10 +1252,10 @@ return true; } -bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) +bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!CheckBlock()) + if (!CheckBlock(!fJustCheck, !fJustCheck)) return false; // Do not allow blocks that contain transactions which 'overwrite' older transactions, @@ -1283,7 +1283,13 @@ bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime); //// issue here: it doesn't know the version - unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); + unsigned int nTxPos; + if (fJustCheck) + // FetchInputs treats CDiskTxPos(1,1,1) as a special "refer to memorypool" indicator + // Since we're just checking the block and not actually connecting it, it might not (and probably shouldn't) be on the disk to get the transaction from + nTxPos = 1; + else + nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); map<uint256, CTxIndex> mapQueuedChanges; int64 nFees = 0; @@ -1295,7 +1301,8 @@ return DoS(100, error("ConnectBlock() : too many sigops")); CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos); - nTxPos += ::GetSerializeSize(tx, SER_DISK); + if (!fJustCheck) + nTxPos += ::GetSerializeSize(tx, SER_DISK); MapPrevTx mapInputs; if (!tx.IsCoinBase()) @@ -1323,6 +1330,12 @@ mapQueuedChanges[tx.GetHash()] = CTxIndex(posThisTx, tx.vout.size()); } + if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) + return false; + + if (fJustCheck) + return true; + // Write queued txindex changes for (map<uint256, CTxIndex>::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi) { @@ -1330,9 +1343,6 @@ return error("ConnectBlock() : UpdateTxIndex failed"); } - if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) - return false; - // Update block index on disk without changing it in memory. // The memory index structure will be changed after the db commits. if (pindex->pprev) @@ -1619,7 +1629,7 @@ -bool CBlock::CheckBlock() const +bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const { // These are checks that are independent of context // that can be verified before saving an orphan block. @@ -1629,7 +1639,7 @@ return DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount - if (!CheckProofOfWork(GetHash(), nBits)) + if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) return DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp @@ -1657,7 +1667,7 @@ return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); // Check merkleroot - if (hashMerkleRoot != BuildMerkleTree()) + if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); return true; @@ -3066,6 +3076,9 @@ uint64 nLastBlockTx = 0; uint64 nLastBlockSize = 0; +const char* pszDummy = "\0\0"; +CScript scriptDummy(std::vector<unsigned char>(pszDummy, pszDummy + sizeof(pszDummy))); + CBlock* CreateNewBlock(CReserveKey& reservekey) { CBlockIndex* pindexPrev = pindexBest; @@ -3224,16 +3237,22 @@ nLastBlockSize = nBlockSize; printf("CreateNewBlock(): total size %lu\n", nBlockSize); - } pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->UpdateTime(pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get()); pblock->nNonce = 0; + pblock->vtx[0].vin[0].scriptSig = scriptDummy; + CBlockIndex indexDummy(1, 1, *pblock); + indexDummy.pprev = pindexPrev; + indexDummy.nHeight = pindexPrev->nHeight + 1; + if (!pblock->ConnectBlock(txdb, &indexDummy, true)) + throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); + } + return pblock.release(); }
--- a/src/main.h +++ b/src/main.h @@ -1017,11 +1017,11 @@ bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); - bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); + bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck=false); bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew); bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); - bool CheckBlock() const; + bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; bool AcceptBlock(); private: