mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 04:52:59 +01:00
Merge pull request #2758 from CodeShark/CBlock-to-core
Finish moving core data structures into core.h.
This commit is contained in:
commit
64225f7ce9
123
src/core.h
123
src/core.h
@ -733,4 +733,127 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CBlock : public CBlockHeader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// network and disk
|
||||||
|
std::vector<CTransaction> vtx;
|
||||||
|
|
||||||
|
// memory only
|
||||||
|
mutable std::vector<uint256> vMerkleTree;
|
||||||
|
|
||||||
|
CBlock()
|
||||||
|
{
|
||||||
|
SetNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlock(const CBlockHeader &header)
|
||||||
|
{
|
||||||
|
SetNull();
|
||||||
|
*((CBlockHeader*)this) = header;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_SERIALIZE
|
||||||
|
(
|
||||||
|
READWRITE(*(CBlockHeader*)this);
|
||||||
|
READWRITE(vtx);
|
||||||
|
)
|
||||||
|
|
||||||
|
void SetNull()
|
||||||
|
{
|
||||||
|
CBlockHeader::SetNull();
|
||||||
|
vtx.clear();
|
||||||
|
vMerkleTree.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlockHeader GetBlockHeader() const
|
||||||
|
{
|
||||||
|
CBlockHeader block;
|
||||||
|
block.nVersion = nVersion;
|
||||||
|
block.hashPrevBlock = hashPrevBlock;
|
||||||
|
block.hashMerkleRoot = hashMerkleRoot;
|
||||||
|
block.nTime = nTime;
|
||||||
|
block.nBits = nBits;
|
||||||
|
block.nNonce = nNonce;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 BuildMerkleTree() const
|
||||||
|
{
|
||||||
|
vMerkleTree.clear();
|
||||||
|
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||||
|
vMerkleTree.push_back(tx.GetHash());
|
||||||
|
int j = 0;
|
||||||
|
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nSize; i += 2)
|
||||||
|
{
|
||||||
|
int i2 = std::min(i+1, nSize-1);
|
||||||
|
vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
|
||||||
|
BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
|
||||||
|
}
|
||||||
|
j += nSize;
|
||||||
|
}
|
||||||
|
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint256 &GetTxHash(unsigned int nIndex) const {
|
||||||
|
assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
|
||||||
|
assert(nIndex < vtx.size());
|
||||||
|
return vMerkleTree[nIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint256> GetMerkleBranch(int nIndex) const
|
||||||
|
{
|
||||||
|
if (vMerkleTree.empty())
|
||||||
|
BuildMerkleTree();
|
||||||
|
std::vector<uint256> vMerkleBranch;
|
||||||
|
int j = 0;
|
||||||
|
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
|
||||||
|
{
|
||||||
|
int i = std::min(nIndex^1, nSize-1);
|
||||||
|
vMerkleBranch.push_back(vMerkleTree[j+i]);
|
||||||
|
nIndex >>= 1;
|
||||||
|
j += nSize;
|
||||||
|
}
|
||||||
|
return vMerkleBranch;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
|
||||||
|
{
|
||||||
|
if (nIndex == -1)
|
||||||
|
return 0;
|
||||||
|
BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
|
||||||
|
{
|
||||||
|
if (nIndex & 1)
|
||||||
|
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
|
||||||
|
else
|
||||||
|
hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
|
||||||
|
nIndex >>= 1;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print() const
|
||||||
|
{
|
||||||
|
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n",
|
||||||
|
GetHash().ToString().c_str(),
|
||||||
|
nVersion,
|
||||||
|
hashPrevBlock.ToString().c_str(),
|
||||||
|
hashMerkleRoot.ToString().c_str(),
|
||||||
|
nTime, nBits, nNonce,
|
||||||
|
vtx.size());
|
||||||
|
for (unsigned int i = 0; i < vtx.size(); i++)
|
||||||
|
{
|
||||||
|
printf(" ");
|
||||||
|
vtx[i].print();
|
||||||
|
}
|
||||||
|
printf(" vMerkleTree: ");
|
||||||
|
for (unsigned int i = 0; i < vMerkleTree.size(); i++)
|
||||||
|
printf("%s ", vMerkleTree[i].ToString().c_str());
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -820,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
|||||||
{
|
{
|
||||||
CBlockIndex* pindex = (*mi).second;
|
CBlockIndex* pindex = (*mi).second;
|
||||||
CBlock block;
|
CBlock block;
|
||||||
block.ReadFromDisk(pindex);
|
ReadBlockFromDisk(block, pindex);
|
||||||
block.BuildMerkleTree();
|
block.BuildMerkleTree();
|
||||||
block.print();
|
block.print();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
208
src/main.cpp
208
src/main.cpp
@ -627,7 +627,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
|
|||||||
if (pcoinsTip->GetCoins(GetHash(), coins)) {
|
if (pcoinsTip->GetCoins(GetHash(), coins)) {
|
||||||
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
|
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
|
||||||
if (pindex) {
|
if (pindex) {
|
||||||
if (!blockTmp.ReadFromDisk(pindex))
|
if (!ReadBlockFromDisk(blockTmp, pindex))
|
||||||
return 0;
|
return 0;
|
||||||
pblock = &blockTmp;
|
pblock = &blockTmp;
|
||||||
}
|
}
|
||||||
@ -1114,7 +1114,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
|
|||||||
|
|
||||||
if (pindexSlow) {
|
if (pindexSlow) {
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (block.ReadFromDisk(pindexSlow)) {
|
if (ReadBlockFromDisk(block, pindexSlow)) {
|
||||||
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
|
||||||
if (tx.GetHash() == hash) {
|
if (tx.GetHash() == hash) {
|
||||||
txOut = tx;
|
txOut = tx;
|
||||||
@ -1146,12 +1146,62 @@ CBlockIndex* FindBlockByHeight(int nHeight)
|
|||||||
return vBlockIndexByHeight[nHeight];
|
return vBlockIndexByHeight[nHeight];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBlock::ReadFromDisk(const CBlockIndex* pindex)
|
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
|
||||||
{
|
{
|
||||||
if (!ReadFromDisk(pindex->GetBlockPos()))
|
// Open history file to append
|
||||||
|
CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
|
||||||
|
if (!fileout)
|
||||||
|
return error("WriteBlockToDisk() : OpenBlockFile failed");
|
||||||
|
|
||||||
|
// Write index header
|
||||||
|
unsigned int nSize = fileout.GetSerializeSize(block);
|
||||||
|
fileout << FLATDATA(Params().MessageStart()) << nSize;
|
||||||
|
|
||||||
|
// Write block
|
||||||
|
long fileOutPos = ftell(fileout);
|
||||||
|
if (fileOutPos < 0)
|
||||||
|
return error("WriteBlockToDisk() : ftell failed");
|
||||||
|
pos.nPos = (unsigned int)fileOutPos;
|
||||||
|
fileout << block;
|
||||||
|
|
||||||
|
// Flush stdio buffers and commit to disk before returning
|
||||||
|
fflush(fileout);
|
||||||
|
if (!IsInitialBlockDownload())
|
||||||
|
FileCommit(fileout);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos)
|
||||||
|
{
|
||||||
|
block.SetNull();
|
||||||
|
|
||||||
|
// Open history file to read
|
||||||
|
CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
|
||||||
|
if (!filein)
|
||||||
|
return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed");
|
||||||
|
|
||||||
|
// Read block
|
||||||
|
try {
|
||||||
|
filein >> block;
|
||||||
|
}
|
||||||
|
catch (std::exception &e) {
|
||||||
|
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the header
|
||||||
|
if (!CheckProofOfWork(block.GetHash(), block.nBits))
|
||||||
|
return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
|
||||||
|
{
|
||||||
|
if (!ReadBlockFromDisk(block, pindex->GetBlockPos()))
|
||||||
return false;
|
return false;
|
||||||
if (GetHash() != pindex->GetBlockHash())
|
if (block.GetHash() != pindex->GetBlockHash())
|
||||||
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
|
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1553,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean)
|
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
|
||||||
{
|
{
|
||||||
assert(pindex == view.GetBestBlock());
|
assert(pindex == view.GetBestBlock());
|
||||||
|
|
||||||
@ -1569,12 +1619,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
|
|||||||
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
|
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
|
||||||
return error("DisconnectBlock() : failure reading undo data");
|
return error("DisconnectBlock() : failure reading undo data");
|
||||||
|
|
||||||
if (blockUndo.vtxundo.size() + 1 != vtx.size())
|
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
|
||||||
return error("DisconnectBlock() : block and undo data inconsistent");
|
return error("DisconnectBlock() : block and undo data inconsistent");
|
||||||
|
|
||||||
// undo transactions in reverse order
|
// undo transactions in reverse order
|
||||||
for (int i = vtx.size() - 1; i >= 0; i--) {
|
for (int i = block.vtx.size() - 1; i >= 0; i--) {
|
||||||
const CTransaction &tx = vtx[i];
|
const CTransaction &tx = block.vtx[i];
|
||||||
uint256 hash = tx.GetHash();
|
uint256 hash = tx.GetHash();
|
||||||
|
|
||||||
// check that all outputs are available
|
// check that all outputs are available
|
||||||
@ -1667,10 +1717,10 @@ void ThreadScriptCheck() {
|
|||||||
scriptcheckqueue.Thread();
|
scriptcheckqueue.Thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck)
|
bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck)
|
||||||
{
|
{
|
||||||
// Check it again in case a previous version let a bad block in
|
// Check it again in case a previous version let a bad block in
|
||||||
if (!CheckBlock(state, !fJustCheck, !fJustCheck))
|
if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// verify that the view's current state corresponds to the previous block
|
// verify that the view's current state corresponds to the previous block
|
||||||
@ -1678,7 +1728,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
|||||||
|
|
||||||
// Special case for the genesis block, skipping connection of its transactions
|
// Special case for the genesis block, skipping connection of its transactions
|
||||||
// (its coinbase is unspendable)
|
// (its coinbase is unspendable)
|
||||||
if (GetHash() == Params().HashGenesisBlock()) {
|
if (block.GetHash() == Params().HashGenesisBlock()) {
|
||||||
view.SetBestBlock(pindex);
|
view.SetBestBlock(pindex);
|
||||||
pindexGenesisBlock = pindex;
|
pindexGenesisBlock = pindex;
|
||||||
return true;
|
return true;
|
||||||
@ -1702,8 +1752,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
|||||||
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
|
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
|
||||||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
|
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
|
||||||
if (fEnforceBIP30) {
|
if (fEnforceBIP30) {
|
||||||
for (unsigned int i=0; i<vtx.size(); i++) {
|
for (unsigned int i = 0; i < block.vtx.size(); i++) {
|
||||||
uint256 hash = GetTxHash(i);
|
uint256 hash = block.GetTxHash(i);
|
||||||
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
|
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
|
||||||
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
|
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
|
||||||
}
|
}
|
||||||
@ -1724,12 +1774,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
|||||||
int64 nFees = 0;
|
int64 nFees = 0;
|
||||||
int nInputs = 0;
|
int nInputs = 0;
|
||||||
unsigned int nSigOps = 0;
|
unsigned int nSigOps = 0;
|
||||||
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size()));
|
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
|
||||||
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
||||||
vPos.reserve(vtx.size());
|
vPos.reserve(block.vtx.size());
|
||||||
for (unsigned int i=0; i<vtx.size(); i++)
|
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||||
{
|
{
|
||||||
const CTransaction &tx = vtx[i];
|
const CTransaction &tx = block.vtx[i];
|
||||||
|
|
||||||
nInputs += tx.vin.size();
|
nInputs += tx.vin.size();
|
||||||
nSigOps += GetLegacySigOpCount(tx);
|
nSigOps += GetLegacySigOpCount(tx);
|
||||||
@ -1760,19 +1810,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
|||||||
}
|
}
|
||||||
|
|
||||||
CTxUndo txundo;
|
CTxUndo txundo;
|
||||||
UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i));
|
UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
blockundo.vtxundo.push_back(txundo);
|
blockundo.vtxundo.push_back(txundo);
|
||||||
|
|
||||||
vPos.push_back(std::make_pair(GetTxHash(i), pos));
|
vPos.push_back(std::make_pair(block.GetTxHash(i), pos));
|
||||||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||||
}
|
}
|
||||||
int64 nTime = GetTimeMicros() - nStart;
|
int64 nTime = GetTimeMicros() - nStart;
|
||||||
if (fBenchmark)
|
if (fBenchmark)
|
||||||
printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
|
printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
|
||||||
|
|
||||||
if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
|
if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
|
||||||
return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
|
return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
|
||||||
|
|
||||||
if (!control.Wait())
|
if (!control.Wait())
|
||||||
return state.DoS(100, false);
|
return state.DoS(100, false);
|
||||||
@ -1813,8 +1863,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
|||||||
assert(view.SetBestBlock(pindex));
|
assert(view.SetBestBlock(pindex));
|
||||||
|
|
||||||
// Watch for transactions paying to me
|
// Watch for transactions paying to me
|
||||||
for (unsigned int i=0; i<vtx.size(); i++)
|
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||||
SyncWithWallets(GetTxHash(i), vtx[i], this, true);
|
SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1860,10 +1910,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
|||||||
vector<CTransaction> vResurrect;
|
vector<CTransaction> vResurrect;
|
||||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (!block.ReadFromDisk(pindex))
|
if (!ReadBlockFromDisk(block, pindex))
|
||||||
return state.Abort(_("Failed to read block"));
|
return state.Abort(_("Failed to read block"));
|
||||||
int64 nStart = GetTimeMicros();
|
int64 nStart = GetTimeMicros();
|
||||||
if (!block.DisconnectBlock(state, pindex, view))
|
if (!DisconnectBlock(block, state, pindex, view))
|
||||||
return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
|
return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str());
|
||||||
if (fBenchmark)
|
if (fBenchmark)
|
||||||
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
|
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
|
||||||
@ -1880,10 +1930,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
|||||||
vector<CTransaction> vDelete;
|
vector<CTransaction> vDelete;
|
||||||
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
|
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (!block.ReadFromDisk(pindex))
|
if (!ReadBlockFromDisk(block, pindex))
|
||||||
return state.Abort(_("Failed to read block"));
|
return state.Abort(_("Failed to read block"));
|
||||||
int64 nStart = GetTimeMicros();
|
int64 nStart = GetTimeMicros();
|
||||||
if (!block.ConnectBlock(state, pindex, view)) {
|
if (!ConnectBlock(block, state, pindex, view)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
InvalidChainFound(pindexNew);
|
InvalidChainFound(pindexNew);
|
||||||
InvalidBlockFound(pindex);
|
InvalidBlockFound(pindex);
|
||||||
@ -1993,25 +2043,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
|
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos)
|
||||||
{
|
{
|
||||||
// Check for duplicate
|
// Check for duplicate
|
||||||
uint256 hash = GetHash();
|
uint256 hash = block.GetHash();
|
||||||
if (mapBlockIndex.count(hash))
|
if (mapBlockIndex.count(hash))
|
||||||
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str()));
|
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str()));
|
||||||
|
|
||||||
// Construct new block index object
|
// Construct new block index object
|
||||||
CBlockIndex* pindexNew = new CBlockIndex(*this);
|
CBlockIndex* pindexNew = new CBlockIndex(block);
|
||||||
assert(pindexNew);
|
assert(pindexNew);
|
||||||
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
|
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
|
||||||
pindexNew->phashBlock = &((*mi).first);
|
pindexNew->phashBlock = &((*mi).first);
|
||||||
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
|
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
|
||||||
if (miPrev != mapBlockIndex.end())
|
if (miPrev != mapBlockIndex.end())
|
||||||
{
|
{
|
||||||
pindexNew->pprev = (*miPrev).second;
|
pindexNew->pprev = (*miPrev).second;
|
||||||
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
|
||||||
}
|
}
|
||||||
pindexNew->nTx = vtx.size();
|
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->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
|
||||||
pindexNew->nFile = pos.nFile;
|
pindexNew->nFile = pos.nFile;
|
||||||
@ -2032,7 +2082,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
|
|||||||
// Notify UI to display prev block's coinbase if it was ours
|
// Notify UI to display prev block's coinbase if it was ours
|
||||||
static uint256 hashPrevBestCoinBase;
|
static uint256 hashPrevBestCoinBase;
|
||||||
UpdatedTransaction(hashPrevBestCoinBase);
|
UpdatedTransaction(hashPrevBestCoinBase);
|
||||||
hashPrevBestCoinBase = GetTxHash(0);
|
hashPrevBestCoinBase = block.GetTxHash(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pblocktree->Flush())
|
if (!pblocktree->Flush())
|
||||||
@ -2138,51 +2188,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const
|
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.
|
||||||
|
|
||||||
// Size limits
|
// Size limits
|
||||||
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, 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"));
|
||||||
|
|
||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits))
|
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits))
|
||||||
return state.DoS(50, error("CheckBlock() : proof of work failed"));
|
return state.DoS(50, error("CheckBlock() : proof of work failed"));
|
||||||
|
|
||||||
// Check timestamp
|
// Check timestamp
|
||||||
if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
|
if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
|
||||||
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"));
|
return state.Invalid(error("CheckBlock() : block timestamp too far in the future"));
|
||||||
|
|
||||||
// First transaction must be coinbase, the rest must not be
|
// First transaction must be coinbase, the rest must not be
|
||||||
if (vtx.empty() || !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"));
|
||||||
for (unsigned int i = 1; i < vtx.size(); i++)
|
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
||||||
if (vtx[i].IsCoinBase())
|
if (block.vtx[i].IsCoinBase())
|
||||||
return state.DoS(100, error("CheckBlock() : more than one coinbase"));
|
return state.DoS(100, error("CheckBlock() : more than one coinbase"));
|
||||||
|
|
||||||
// Check transactions
|
// Check transactions
|
||||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
if (!CheckTransaction(tx, state))
|
if (!CheckTransaction(tx, state))
|
||||||
return error("CheckBlock() : CheckTransaction failed");
|
return error("CheckBlock() : CheckTransaction failed");
|
||||||
|
|
||||||
// Build the merkle tree already. We need it anyway later, and it makes the
|
// Build the merkle tree already. We need it anyway later, and it makes the
|
||||||
// block cache the transaction hashes, which means they don't need to be
|
// block cache the transaction hashes, which means they don't need to be
|
||||||
// recalculated many times during this block's validation.
|
// recalculated many times during this block's validation.
|
||||||
BuildMerkleTree();
|
block.BuildMerkleTree();
|
||||||
|
|
||||||
// Check for duplicate txids. This is caught by ConnectInputs(),
|
// Check for duplicate txids. This is caught by ConnectInputs(),
|
||||||
// but catching it earlier avoids a potential DoS attack:
|
// but catching it earlier avoids a potential DoS attack:
|
||||||
set<uint256> uniqueTx;
|
set<uint256> uniqueTx;
|
||||||
for (unsigned int i=0; i<vtx.size(); i++) {
|
for (unsigned int i = 0; i < block.vtx.size(); i++) {
|
||||||
uniqueTx.insert(GetTxHash(i));
|
uniqueTx.insert(block.GetTxHash(i));
|
||||||
}
|
}
|
||||||
if (uniqueTx.size() != vtx.size())
|
if (uniqueTx.size() != block.vtx.size())
|
||||||
return state.DoS(100, error("CheckBlock() : duplicate transaction"));
|
return state.DoS(100, error("CheckBlock() : duplicate transaction"));
|
||||||
|
|
||||||
unsigned int nSigOps = 0;
|
unsigned int nSigOps = 0;
|
||||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
{
|
{
|
||||||
nSigOps += GetLegacySigOpCount(tx);
|
nSigOps += GetLegacySigOpCount(tx);
|
||||||
}
|
}
|
||||||
@ -2190,16 +2240,16 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
|
|||||||
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
|
return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
|
||||||
|
|
||||||
// Check merkle root
|
// Check merkle root
|
||||||
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
|
if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
|
||||||
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
|
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
||||||
{
|
{
|
||||||
// Check for duplicate
|
// Check for duplicate
|
||||||
uint256 hash = GetHash();
|
uint256 hash = block.GetHash();
|
||||||
if (mapBlockIndex.count(hash))
|
if (mapBlockIndex.count(hash))
|
||||||
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
|
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
|
||||||
|
|
||||||
@ -2207,23 +2257,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
|||||||
CBlockIndex* pindexPrev = NULL;
|
CBlockIndex* pindexPrev = NULL;
|
||||||
int nHeight = 0;
|
int nHeight = 0;
|
||||||
if (hash != Params().HashGenesisBlock()) {
|
if (hash != Params().HashGenesisBlock()) {
|
||||||
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
|
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
|
||||||
if (mi == mapBlockIndex.end())
|
if (mi == mapBlockIndex.end())
|
||||||
return state.DoS(10, error("AcceptBlock() : prev block not found"));
|
return state.DoS(10, error("AcceptBlock() : prev block not found"));
|
||||||
pindexPrev = (*mi).second;
|
pindexPrev = (*mi).second;
|
||||||
nHeight = pindexPrev->nHeight+1;
|
nHeight = pindexPrev->nHeight+1;
|
||||||
|
|
||||||
// Check proof of work
|
// Check proof of work
|
||||||
if (nBits != GetNextWorkRequired(pindexPrev, this))
|
if (block.nBits != GetNextWorkRequired(pindexPrev, &block))
|
||||||
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"));
|
return state.DoS(100, error("AcceptBlock() : incorrect proof of work"));
|
||||||
|
|
||||||
// Check timestamp against prev
|
// Check timestamp against prev
|
||||||
if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
||||||
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
|
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
|
||||||
|
|
||||||
// Check that all transactions are finalized
|
// Check that all transactions are finalized
|
||||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||||
if (!IsFinalTx(tx, nHeight, GetBlockTime()))
|
if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
|
||||||
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"));
|
return state.DoS(10, error("AcceptBlock() : contains a non-final transaction"));
|
||||||
|
|
||||||
// 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
|
||||||
@ -2231,7 +2281,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
|||||||
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));
|
||||||
|
|
||||||
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
|
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
|
||||||
if (nVersion < 2)
|
if (block.nVersion < 2)
|
||||||
{
|
{
|
||||||
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
|
if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) ||
|
||||||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
|
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100)))
|
||||||
@ -2240,14 +2290,14 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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 (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, pindexPrev, 750, 1000)) ||
|
||||||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
|
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
|
||||||
{
|
{
|
||||||
CScript expect = CScript() << nHeight;
|
CScript expect = CScript() << nHeight;
|
||||||
if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
|
if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin()))
|
||||||
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
|
return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2255,16 +2305,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
|||||||
|
|
||||||
// Write block to history file
|
// Write block to history file
|
||||||
try {
|
try {
|
||||||
unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
|
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
|
||||||
CDiskBlockPos blockPos;
|
CDiskBlockPos blockPos;
|
||||||
if (dbp != NULL)
|
if (dbp != NULL)
|
||||||
blockPos = *dbp;
|
blockPos = *dbp;
|
||||||
if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL))
|
if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL))
|
||||||
return error("AcceptBlock() : FindBlockPos failed");
|
return error("AcceptBlock() : FindBlockPos failed");
|
||||||
if (dbp == NULL)
|
if (dbp == NULL)
|
||||||
if (!WriteToDisk(blockPos))
|
if (!WriteBlockToDisk(block, blockPos))
|
||||||
return state.Abort(_("Failed to write block"));
|
return state.Abort(_("Failed to write block"));
|
||||||
if (!AddToBlockIndex(state, blockPos))
|
if (!AddToBlockIndex(block, state, blockPos))
|
||||||
return error("AcceptBlock() : AddToBlockIndex failed");
|
return error("AcceptBlock() : AddToBlockIndex 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());
|
||||||
@ -2316,7 +2366,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||||||
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str()));
|
return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str()));
|
||||||
|
|
||||||
// Preliminary checks
|
// Preliminary checks
|
||||||
if (!pblock->CheckBlock(state))
|
if (!CheckBlock(*pblock, state))
|
||||||
return error("ProcessBlock() : CheckBlock FAILED");
|
return error("ProcessBlock() : CheckBlock FAILED");
|
||||||
|
|
||||||
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
|
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
|
||||||
@ -2357,7 +2407,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store to disk
|
// Store to disk
|
||||||
if (!pblock->AcceptBlock(state, dbp))
|
if (!AcceptBlock(*pblock, state, dbp))
|
||||||
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
|
||||||
@ -2373,7 +2423,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
|||||||
CBlock* pblockOrphan = (*mi).second;
|
CBlock* pblockOrphan = (*mi).second;
|
||||||
// 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 (pblockOrphan->AcceptBlock(stateDummy))
|
if (AcceptBlock(*pblockOrphan, stateDummy))
|
||||||
vWorkQueue.push_back(pblockOrphan->GetHash());
|
vWorkQueue.push_back(pblockOrphan->GetHash());
|
||||||
mapOrphanBlocks.erase(pblockOrphan->GetHash());
|
mapOrphanBlocks.erase(pblockOrphan->GetHash());
|
||||||
delete pblockOrphan;
|
delete pblockOrphan;
|
||||||
@ -2710,10 +2760,10 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
|||||||
break;
|
break;
|
||||||
CBlock block;
|
CBlock block;
|
||||||
// check level 0: read from disk
|
// check level 0: read from disk
|
||||||
if (!block.ReadFromDisk(pindex))
|
if (!ReadBlockFromDisk(block, pindex))
|
||||||
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||||
// check level 1: verify block validity
|
// check level 1: verify block validity
|
||||||
if (nCheckLevel >= 1 && !block.CheckBlock(state))
|
if (nCheckLevel >= 1 && !CheckBlock(block, state))
|
||||||
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||||
// check level 2: verify undo validity
|
// check level 2: verify undo validity
|
||||||
if (nCheckLevel >= 2 && pindex) {
|
if (nCheckLevel >= 2 && pindex) {
|
||||||
@ -2727,7 +2777,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
|||||||
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
|
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
|
||||||
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
|
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
|
||||||
bool fClean = true;
|
bool fClean = true;
|
||||||
if (!block.DisconnectBlock(state, pindex, coins, &fClean))
|
if (!DisconnectBlock(block, state, pindex, coins, &fClean))
|
||||||
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||||
pindexState = pindex->pprev;
|
pindexState = pindex->pprev;
|
||||||
if (!fClean) {
|
if (!fClean) {
|
||||||
@ -2747,9 +2797,9 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
|||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
pindex = pindex->GetNextInMainChain();
|
pindex = pindex->GetNextInMainChain();
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (!block.ReadFromDisk(pindex))
|
if (!ReadBlockFromDisk(block, pindex))
|
||||||
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||||
if (!block.ConnectBlock(state, pindex, coins))
|
if (!ConnectBlock(block, state, pindex, coins))
|
||||||
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2800,9 +2850,9 @@ bool InitBlockIndex() {
|
|||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
|
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
|
||||||
return error("LoadBlockIndex() : FindBlockPos failed");
|
return error("LoadBlockIndex() : FindBlockPos failed");
|
||||||
if (!block.WriteToDisk(blockPos))
|
if (!WriteBlockToDisk(block, blockPos))
|
||||||
return error("LoadBlockIndex() : writing genesis block to disk failed");
|
return error("LoadBlockIndex() : writing genesis block to disk failed");
|
||||||
if (!block.AddToBlockIndex(state, blockPos))
|
if (!AddToBlockIndex(block, state, 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());
|
||||||
@ -2858,7 +2908,7 @@ void PrintBlockTree()
|
|||||||
|
|
||||||
// print item
|
// print item
|
||||||
CBlock block;
|
CBlock block;
|
||||||
block.ReadFromDisk(pindex);
|
ReadBlockFromDisk(block, pindex);
|
||||||
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
|
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
|
||||||
pindex->nHeight,
|
pindex->nHeight,
|
||||||
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
|
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
|
||||||
@ -3082,7 +3132,7 @@ void static ProcessGetData(CNode* pfrom)
|
|||||||
if (mi != mapBlockIndex.end())
|
if (mi != mapBlockIndex.end())
|
||||||
{
|
{
|
||||||
CBlock block;
|
CBlock block;
|
||||||
block.ReadFromDisk((*mi).second);
|
ReadBlockFromDisk(block, (*mi).second);
|
||||||
if (inv.type == MSG_BLOCK)
|
if (inv.type == MSG_BLOCK)
|
||||||
pfrom->PushMessage("block", block);
|
pfrom->PushMessage("block", block);
|
||||||
else // MSG_FILTERED_BLOCK)
|
else // MSG_FILTERED_BLOCK)
|
||||||
@ -4404,7 +4454,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
|
|||||||
indexDummy.nHeight = pindexPrev->nHeight + 1;
|
indexDummy.nHeight = pindexPrev->nHeight + 1;
|
||||||
CCoinsViewCache viewNew(*pcoinsTip, true);
|
CCoinsViewCache viewNew(*pcoinsTip, true);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true))
|
if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
|
||||||
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
|
throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
209
src/main.h
209
src/main.h
@ -581,204 +581,33 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CBlock : public CBlockHeader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// network and disk
|
|
||||||
std::vector<CTransaction> vtx;
|
|
||||||
|
|
||||||
// memory only
|
/** Functions for disk access for blocks */
|
||||||
mutable std::vector<uint256> vMerkleTree;
|
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
|
||||||
|
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
|
||||||
CBlock()
|
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
CBlock(const CBlockHeader &header)
|
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
*((CBlockHeader*)this) = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMPLEMENT_SERIALIZE
|
|
||||||
(
|
|
||||||
READWRITE(*(CBlockHeader*)this);
|
|
||||||
READWRITE(vtx);
|
|
||||||
)
|
|
||||||
|
|
||||||
void SetNull()
|
|
||||||
{
|
|
||||||
CBlockHeader::SetNull();
|
|
||||||
vtx.clear();
|
|
||||||
vMerkleTree.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CBlockHeader GetBlockHeader() const
|
|
||||||
{
|
|
||||||
CBlockHeader block;
|
|
||||||
block.nVersion = nVersion;
|
|
||||||
block.hashPrevBlock = hashPrevBlock;
|
|
||||||
block.hashMerkleRoot = hashMerkleRoot;
|
|
||||||
block.nTime = nTime;
|
|
||||||
block.nBits = nBits;
|
|
||||||
block.nNonce = nNonce;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint256 BuildMerkleTree() const
|
|
||||||
{
|
|
||||||
vMerkleTree.clear();
|
|
||||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
|
||||||
vMerkleTree.push_back(tx.GetHash());
|
|
||||||
int j = 0;
|
|
||||||
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < nSize; i += 2)
|
|
||||||
{
|
|
||||||
int i2 = std::min(i+1, nSize-1);
|
|
||||||
vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]),
|
|
||||||
BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
|
|
||||||
}
|
|
||||||
j += nSize;
|
|
||||||
}
|
|
||||||
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint256 &GetTxHash(unsigned int nIndex) const {
|
|
||||||
assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
|
|
||||||
assert(nIndex < vtx.size());
|
|
||||||
return vMerkleTree[nIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint256> GetMerkleBranch(int nIndex) const
|
|
||||||
{
|
|
||||||
if (vMerkleTree.empty())
|
|
||||||
BuildMerkleTree();
|
|
||||||
std::vector<uint256> vMerkleBranch;
|
|
||||||
int j = 0;
|
|
||||||
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
|
|
||||||
{
|
|
||||||
int i = std::min(nIndex^1, nSize-1);
|
|
||||||
vMerkleBranch.push_back(vMerkleTree[j+i]);
|
|
||||||
nIndex >>= 1;
|
|
||||||
j += nSize;
|
|
||||||
}
|
|
||||||
return vMerkleBranch;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
|
|
||||||
{
|
|
||||||
if (nIndex == -1)
|
|
||||||
return 0;
|
|
||||||
BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
|
|
||||||
{
|
|
||||||
if (nIndex & 1)
|
|
||||||
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
|
|
||||||
else
|
|
||||||
hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
|
|
||||||
nIndex >>= 1;
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WriteToDisk(CDiskBlockPos &pos)
|
|
||||||
{
|
|
||||||
// Open history file to append
|
|
||||||
CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
|
|
||||||
if (!fileout)
|
|
||||||
return error("CBlock::WriteToDisk() : OpenBlockFile failed");
|
|
||||||
|
|
||||||
// Write index header
|
|
||||||
unsigned int nSize = fileout.GetSerializeSize(*this);
|
|
||||||
fileout << FLATDATA(Params().MessageStart()) << nSize;
|
|
||||||
|
|
||||||
// Write block
|
|
||||||
long fileOutPos = ftell(fileout);
|
|
||||||
if (fileOutPos < 0)
|
|
||||||
return error("CBlock::WriteToDisk() : ftell failed");
|
|
||||||
pos.nPos = (unsigned int)fileOutPos;
|
|
||||||
fileout << *this;
|
|
||||||
|
|
||||||
// Flush stdio buffers and commit to disk before returning
|
|
||||||
fflush(fileout);
|
|
||||||
if (!IsInitialBlockDownload())
|
|
||||||
FileCommit(fileout);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadFromDisk(const CDiskBlockPos &pos)
|
|
||||||
{
|
|
||||||
SetNull();
|
|
||||||
|
|
||||||
// Open history file to read
|
|
||||||
CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
|
|
||||||
if (!filein)
|
|
||||||
return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
|
|
||||||
|
|
||||||
// Read block
|
|
||||||
try {
|
|
||||||
filein >> *this;
|
|
||||||
}
|
|
||||||
catch (std::exception &e) {
|
|
||||||
return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the header
|
|
||||||
if (!CheckProofOfWork(GetHash(), nBits))
|
|
||||||
return error("CBlock::ReadFromDisk() : errors in block header");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Functions for validating blocks and updating the block tree */
|
||||||
|
|
||||||
void print() const
|
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
|
||||||
{
|
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
|
||||||
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n",
|
* will be true if no problems were found. Otherwise, the return value will be false in case
|
||||||
GetHash().ToString().c_str(),
|
* of problems. Note that in any case, coins may be modified. */
|
||||||
nVersion,
|
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
|
||||||
hashPrevBlock.ToString().c_str(),
|
|
||||||
hashMerkleRoot.ToString().c_str(),
|
|
||||||
nTime, nBits, nNonce,
|
|
||||||
vtx.size());
|
|
||||||
for (unsigned int i = 0; i < vtx.size(); i++)
|
|
||||||
{
|
|
||||||
printf(" ");
|
|
||||||
vtx[i].print();
|
|
||||||
}
|
|
||||||
printf(" vMerkleTree: ");
|
|
||||||
for (unsigned int i = 0; i < vMerkleTree.size(); i++)
|
|
||||||
printf("%s ", vMerkleTree[i].ToString().c_str());
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Apply the effects of this block (with given index) on the UTXO set represented by coins
|
||||||
|
bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
|
||||||
|
|
||||||
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
|
// Add this block to the block index, and if necessary, switch the active block chain to this
|
||||||
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
|
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
||||||
* will be true if no problems were found. Otherwise, the return value will be false in case
|
|
||||||
* of problems. Note that in any case, coins may be modified. */
|
|
||||||
bool DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL);
|
|
||||||
|
|
||||||
// Apply the effects of this block (with given index) on the UTXO set represented by coins
|
|
||||||
bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false);
|
|
||||||
|
|
||||||
// Read a block from disk
|
|
||||||
bool ReadFromDisk(const CBlockIndex* pindex);
|
|
||||||
|
|
||||||
// Add this block to the block index, and if necessary, switch the active block chain to this
|
|
||||||
bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos);
|
|
||||||
|
|
||||||
// Context-independent validity checks
|
|
||||||
bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const;
|
|
||||||
|
|
||||||
// Store block on disk
|
|
||||||
// if dbp is provided, the file is known to already reside on disk
|
|
||||||
bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Context-independent validity checks
|
||||||
|
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
|
// Store block on disk
|
||||||
|
// if dbp is provided, the file is known to already reside on disk
|
||||||
|
bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ Value getblock(const Array& params, bool fHelp)
|
|||||||
|
|
||||||
CBlock block;
|
CBlock block;
|
||||||
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||||
block.ReadFromDisk(pblockindex);
|
ReadBlockFromDisk(block, pblockindex);
|
||||||
|
|
||||||
if (!fVerbose)
|
if (!fVerbose)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15)
|
|||||||
|
|
||||||
// After May 15'th, big blocks are OK:
|
// After May 15'th, big blocks are OK:
|
||||||
forkingBlock.nTime = tMay15; // Invalidates PoW
|
forkingBlock.nTime = tMay15; // Invalidates PoW
|
||||||
BOOST_CHECK(forkingBlock.CheckBlock(state, false, false));
|
BOOST_CHECK(CheckBlock(forkingBlock, state, false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
SetMockTime(0);
|
SetMockTime(0);
|
||||||
|
@ -804,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CBlock block;
|
CBlock block;
|
||||||
block.ReadFromDisk(pindex);
|
ReadBlockFromDisk(block, pindex);
|
||||||
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
||||||
{
|
{
|
||||||
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
|
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
|
||||||
|
Loading…
Reference in New Issue
Block a user