mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +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
|
||||
|
@ -820,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
{
|
||||
CBlockIndex* pindex = (*mi).second;
|
||||
CBlock block;
|
||||
block.ReadFromDisk(pindex);
|
||||
ReadBlockFromDisk(block, pindex);
|
||||
block.BuildMerkleTree();
|
||||
block.print();
|
||||
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)) {
|
||||
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
|
||||
if (pindex) {
|
||||
if (!blockTmp.ReadFromDisk(pindex))
|
||||
if (!ReadBlockFromDisk(blockTmp, pindex))
|
||||
return 0;
|
||||
pblock = &blockTmp;
|
||||
}
|
||||
@ -1114,7 +1114,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
|
||||
|
||||
if (pindexSlow) {
|
||||
CBlock block;
|
||||
if (block.ReadFromDisk(pindexSlow)) {
|
||||
if (ReadBlockFromDisk(block, pindexSlow)) {
|
||||
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
|
||||
if (tx.GetHash() == hash) {
|
||||
txOut = tx;
|
||||
@ -1146,12 +1146,62 @@ CBlockIndex* FindBlockByHeight(int 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;
|
||||
if (GetHash() != pindex->GetBlockHash())
|
||||
return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
|
||||
if (block.GetHash() != pindex->GetBlockHash())
|
||||
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index");
|
||||
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());
|
||||
|
||||
@ -1569,12 +1619,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
|
||||
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
|
||||
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");
|
||||
|
||||
// undo transactions in reverse order
|
||||
for (int i = vtx.size() - 1; i >= 0; i--) {
|
||||
const CTransaction &tx = vtx[i];
|
||||
for (int i = block.vtx.size() - 1; i >= 0; i--) {
|
||||
const CTransaction &tx = block.vtx[i];
|
||||
uint256 hash = tx.GetHash();
|
||||
|
||||
// check that all outputs are available
|
||||
@ -1667,10 +1717,10 @@ void ThreadScriptCheck() {
|
||||
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
|
||||
if (!CheckBlock(state, !fJustCheck, !fJustCheck))
|
||||
if (!CheckBlock(block, state, !fJustCheck, !fJustCheck))
|
||||
return false;
|
||||
|
||||
// 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
|
||||
// (its coinbase is unspendable)
|
||||
if (GetHash() == Params().HashGenesisBlock()) {
|
||||
if (block.GetHash() == Params().HashGenesisBlock()) {
|
||||
view.SetBestBlock(pindex);
|
||||
pindexGenesisBlock = pindex;
|
||||
return true;
|
||||
@ -1702,8 +1752,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
||||
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
|
||||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
|
||||
if (fEnforceBIP30) {
|
||||
for (unsigned int i=0; i<vtx.size(); i++) {
|
||||
uint256 hash = GetTxHash(i);
|
||||
for (unsigned int i = 0; i < block.vtx.size(); i++) {
|
||||
uint256 hash = block.GetTxHash(i);
|
||||
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned())
|
||||
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;
|
||||
int nInputs = 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;
|
||||
vPos.reserve(vtx.size());
|
||||
for (unsigned int i=0; i<vtx.size(); i++)
|
||||
vPos.reserve(block.vtx.size());
|
||||
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();
|
||||
nSigOps += GetLegacySigOpCount(tx);
|
||||
@ -1760,19 +1810,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
||||
}
|
||||
|
||||
CTxUndo txundo;
|
||||
UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i));
|
||||
UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i));
|
||||
if (!tx.IsCoinBase())
|
||||
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);
|
||||
}
|
||||
int64 nTime = GetTimeMicros() - nStart;
|
||||
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))
|
||||
return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", 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(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)));
|
||||
|
||||
if (!control.Wait())
|
||||
return state.DoS(100, false);
|
||||
@ -1813,8 +1863,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
|
||||
assert(view.SetBestBlock(pindex));
|
||||
|
||||
// Watch for transactions paying to me
|
||||
for (unsigned int i=0; i<vtx.size(); i++)
|
||||
SyncWithWallets(GetTxHash(i), vtx[i], this, true);
|
||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||
SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1860,10 +1910,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
||||
vector<CTransaction> vResurrect;
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) {
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return state.Abort(_("Failed to read block"));
|
||||
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());
|
||||
if (fBenchmark)
|
||||
printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
|
||||
@ -1880,10 +1930,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
|
||||
vector<CTransaction> vDelete;
|
||||
BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return state.Abort(_("Failed to read block"));
|
||||
int64 nStart = GetTimeMicros();
|
||||
if (!block.ConnectBlock(state, pindex, view)) {
|
||||
if (!ConnectBlock(block, state, pindex, view)) {
|
||||
if (state.IsInvalid()) {
|
||||
InvalidChainFound(pindexNew);
|
||||
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
|
||||
uint256 hash = GetHash();
|
||||
uint256 hash = block.GetHash();
|
||||
if (mapBlockIndex.count(hash))
|
||||
return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str()));
|
||||
|
||||
// Construct new block index object
|
||||
CBlockIndex* pindexNew = new CBlockIndex(*this);
|
||||
CBlockIndex* pindexNew = new CBlockIndex(block);
|
||||
assert(pindexNew);
|
||||
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).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())
|
||||
{
|
||||
pindexNew->pprev = (*miPrev).second;
|
||||
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->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
|
||||
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
|
||||
static uint256 hashPrevBestCoinBase;
|
||||
UpdatedTransaction(hashPrevBestCoinBase);
|
||||
hashPrevBestCoinBase = GetTxHash(0);
|
||||
hashPrevBestCoinBase = block.GetTxHash(0);
|
||||
}
|
||||
|
||||
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
|
||||
// that can be verified before saving an orphan block.
|
||||
|
||||
// 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"));
|
||||
|
||||
// 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"));
|
||||
|
||||
// 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"));
|
||||
|
||||
// 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"));
|
||||
for (unsigned int i = 1; i < vtx.size(); i++)
|
||||
if (vtx[i].IsCoinBase())
|
||||
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
||||
if (block.vtx[i].IsCoinBase())
|
||||
return state.DoS(100, error("CheckBlock() : more than one coinbase"));
|
||||
|
||||
// Check transactions
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
if (!CheckTransaction(tx, state))
|
||||
return error("CheckBlock() : CheckTransaction failed");
|
||||
|
||||
// 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
|
||||
// recalculated many times during this block's validation.
|
||||
BuildMerkleTree();
|
||||
block.BuildMerkleTree();
|
||||
|
||||
// Check for duplicate txids. This is caught by ConnectInputs(),
|
||||
// but catching it earlier avoids a potential DoS attack:
|
||||
set<uint256> uniqueTx;
|
||||
for (unsigned int i=0; i<vtx.size(); i++) {
|
||||
uniqueTx.insert(GetTxHash(i));
|
||||
for (unsigned int i = 0; i < block.vtx.size(); 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"));
|
||||
|
||||
unsigned int nSigOps = 0;
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
{
|
||||
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"));
|
||||
|
||||
// Check merkle root
|
||||
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
|
||||
if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree())
|
||||
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
||||
bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
||||
{
|
||||
// Check for duplicate
|
||||
uint256 hash = GetHash();
|
||||
uint256 hash = block.GetHash();
|
||||
if (mapBlockIndex.count(hash))
|
||||
return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex"));
|
||||
|
||||
@ -2207,23 +2257,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
||||
CBlockIndex* pindexPrev = NULL;
|
||||
int nHeight = 0;
|
||||
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())
|
||||
return state.DoS(10, error("AcceptBlock() : prev block not found"));
|
||||
pindexPrev = (*mi).second;
|
||||
nHeight = pindexPrev->nHeight+1;
|
||||
|
||||
// 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"));
|
||||
|
||||
// Check timestamp against prev
|
||||
if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
||||
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
||||
return state.Invalid(error("AcceptBlock() : block's timestamp is too early"));
|
||||
|
||||
// Check that all transactions are finalized
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
if (!IsFinalTx(tx, nHeight, GetBlockTime()))
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
if (!IsFinalTx(tx, nHeight, block.GetBlockTime()))
|
||||
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
|
||||
@ -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));
|
||||
|
||||
// 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)) ||
|
||||
(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
|
||||
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 ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) ||
|
||||
(TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100)))
|
||||
{
|
||||
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"));
|
||||
}
|
||||
}
|
||||
@ -2255,16 +2305,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
|
||||
|
||||
// Write block to history file
|
||||
try {
|
||||
unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION);
|
||||
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
|
||||
CDiskBlockPos blockPos;
|
||||
if (dbp != NULL)
|
||||
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");
|
||||
if (dbp == NULL)
|
||||
if (!WriteToDisk(blockPos))
|
||||
if (!WriteBlockToDisk(block, blockPos))
|
||||
return state.Abort(_("Failed to write block"));
|
||||
if (!AddToBlockIndex(state, blockPos))
|
||||
if (!AddToBlockIndex(block, state, blockPos))
|
||||
return error("AcceptBlock() : AddToBlockIndex failed");
|
||||
} catch(std::runtime_error &e) {
|
||||
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()));
|
||||
|
||||
// Preliminary checks
|
||||
if (!pblock->CheckBlock(state))
|
||||
if (!CheckBlock(*pblock, state))
|
||||
return error("ProcessBlock() : CheckBlock FAILED");
|
||||
|
||||
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
|
||||
@ -2357,7 +2407,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
|
||||
}
|
||||
|
||||
// Store to disk
|
||||
if (!pblock->AcceptBlock(state, dbp))
|
||||
if (!AcceptBlock(*pblock, state, dbp))
|
||||
return error("ProcessBlock() : AcceptBlock FAILED");
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
if (pblockOrphan->AcceptBlock(stateDummy))
|
||||
if (AcceptBlock(*pblockOrphan, stateDummy))
|
||||
vWorkQueue.push_back(pblockOrphan->GetHash());
|
||||
mapOrphanBlocks.erase(pblockOrphan->GetHash());
|
||||
delete pblockOrphan;
|
||||
@ -2710,10 +2760,10 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
||||
break;
|
||||
CBlock block;
|
||||
// check level 0: read from disk
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||
// 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());
|
||||
// check level 2: verify undo validity
|
||||
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
|
||||
if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
|
||||
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());
|
||||
pindexState = pindex->pprev;
|
||||
if (!fClean) {
|
||||
@ -2747,9 +2797,9 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
|
||||
boost::this_thread::interruption_point();
|
||||
pindex = pindex->GetNextInMainChain();
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||
if (!block.ConnectBlock(state, pindex, coins))
|
||||
if (!ReadBlockFromDisk(block, pindex))
|
||||
return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||
if (!ConnectBlock(block, state, pindex, coins))
|
||||
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;
|
||||
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime))
|
||||
return error("LoadBlockIndex() : FindBlockPos failed");
|
||||
if (!block.WriteToDisk(blockPos))
|
||||
if (!WriteBlockToDisk(block, blockPos))
|
||||
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");
|
||||
} catch(std::runtime_error &e) {
|
||||
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
|
||||
@ -2858,7 +2908,7 @@ void PrintBlockTree()
|
||||
|
||||
// print item
|
||||
CBlock block;
|
||||
block.ReadFromDisk(pindex);
|
||||
ReadBlockFromDisk(block, pindex);
|
||||
printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"",
|
||||
pindex->nHeight,
|
||||
pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos,
|
||||
@ -3082,7 +3132,7 @@ void static ProcessGetData(CNode* pfrom)
|
||||
if (mi != mapBlockIndex.end())
|
||||
{
|
||||
CBlock block;
|
||||
block.ReadFromDisk((*mi).second);
|
||||
ReadBlockFromDisk(block, (*mi).second);
|
||||
if (inv.type == MSG_BLOCK)
|
||||
pfrom->PushMessage("block", block);
|
||||
else // MSG_FILTERED_BLOCK)
|
||||
@ -4404,7 +4454,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
|
||||
indexDummy.nHeight = pindexPrev->nHeight + 1;
|
||||
CCoinsViewCache viewNew(*pcoinsTip, true);
|
||||
CValidationState state;
|
||||
if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true))
|
||||
if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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 disk access for blocks */
|
||||
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
|
||||
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
|
||||
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
|
||||
|
||||
|
||||
/** Functions for validating blocks and updating the block tree */
|
||||
|
||||
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");
|
||||
}
|
||||
/** 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
|
||||
* 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(CBlock& block, 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(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.
|
||||
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
|
||||
* 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);
|
||||
};
|
||||
// Add this block to the block index, and if necessary, switch the active block chain to this
|
||||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
||||
|
||||
// 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;
|
||||
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||
block.ReadFromDisk(pblockindex);
|
||||
ReadBlockFromDisk(block, pblockindex);
|
||||
|
||||
if (!fVerbose)
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15)
|
||||
|
||||
// After May 15'th, big blocks are OK:
|
||||
forkingBlock.nTime = tMay15; // Invalidates PoW
|
||||
BOOST_CHECK(forkingBlock.CheckBlock(state, false, false));
|
||||
BOOST_CHECK(CheckBlock(forkingBlock, state, false, false));
|
||||
}
|
||||
|
||||
SetMockTime(0);
|
||||
|
@ -804,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
}
|
||||
|
||||
CBlock block;
|
||||
block.ReadFromDisk(pindex);
|
||||
ReadBlockFromDisk(block, pindex);
|
||||
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
||||
{
|
||||
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
|
||||
|
Loading…
Reference in New Issue
Block a user