|
|
|
@ -17,6 +17,7 @@
|
|
|
|
|
#include "txdb.h"
|
|
|
|
|
#include "txmempool.h"
|
|
|
|
|
#include "ui_interface.h"
|
|
|
|
|
#include "undo.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "utilmoneystr.h"
|
|
|
|
|
|
|
|
|
@ -1383,9 +1384,20 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
|
|
|
|
if (!tx.IsCoinBase()) {
|
|
|
|
|
txundo.vprevout.reserve(tx.vin.size());
|
|
|
|
|
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
|
|
|
|
txundo.vprevout.push_back(CTxInUndo());
|
|
|
|
|
bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back());
|
|
|
|
|
assert(ret);
|
|
|
|
|
CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash);
|
|
|
|
|
unsigned nPos = txin.prevout.n;
|
|
|
|
|
|
|
|
|
|
if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull())
|
|
|
|
|
assert(false);
|
|
|
|
|
// mark an outpoint spent, and construct undo information
|
|
|
|
|
txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos]));
|
|
|
|
|
coins->Spend(nPos);
|
|
|
|
|
if (coins->vout.size() == 0) {
|
|
|
|
|
CTxInUndo& undo = txundo.vprevout.back();
|
|
|
|
|
undo.nHeight = coins->nHeight;
|
|
|
|
|
undo.fCoinBase = coins->fCoinBase;
|
|
|
|
|
undo.nVersion = coins->nVersion;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1393,6 +1405,12 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
|
|
|
|
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight)
|
|
|
|
|
{
|
|
|
|
|
CTxUndo txundo;
|
|
|
|
|
UpdateCoins(tx, state, inputs, txundo, nHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CScriptCheck::operator()() {
|
|
|
|
|
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
|
|
|
|
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore), &error)) {
|
|
|
|
@ -1503,7 +1521,63 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock)
|
|
|
|
|
{
|
|
|
|
|
// Open history file to append
|
|
|
|
|
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
|
|
|
|
|
if (fileout.IsNull())
|
|
|
|
|
return error("%s : OpenUndoFile failed", __func__);
|
|
|
|
|
|
|
|
|
|
// Write index header
|
|
|
|
|
unsigned int nSize = fileout.GetSerializeSize(blockundo);
|
|
|
|
|
fileout << FLATDATA(Params().MessageStart()) << nSize;
|
|
|
|
|
|
|
|
|
|
// Write undo data
|
|
|
|
|
long fileOutPos = ftell(fileout.Get());
|
|
|
|
|
if (fileOutPos < 0)
|
|
|
|
|
return error("%s : ftell failed", __func__);
|
|
|
|
|
pos.nPos = (unsigned int)fileOutPos;
|
|
|
|
|
fileout << blockundo;
|
|
|
|
|
|
|
|
|
|
// calculate & write checksum
|
|
|
|
|
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
|
|
|
|
hasher << hashBlock;
|
|
|
|
|
hasher << blockundo;
|
|
|
|
|
fileout << hasher.GetHash();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock)
|
|
|
|
|
{
|
|
|
|
|
// Open history file to read
|
|
|
|
|
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
|
|
|
|
|
if (filein.IsNull())
|
|
|
|
|
return error("%s : OpenBlockFile failed", __func__);
|
|
|
|
|
|
|
|
|
|
// Read block
|
|
|
|
|
uint256 hashChecksum;
|
|
|
|
|
try {
|
|
|
|
|
filein >> blockundo;
|
|
|
|
|
filein >> hashChecksum;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& e) {
|
|
|
|
|
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify checksum
|
|
|
|
|
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
|
|
|
|
hasher << hashBlock;
|
|
|
|
|
hasher << blockundo;
|
|
|
|
|
if (hashChecksum != hasher.GetHash())
|
|
|
|
|
return error("%s : Checksum mismatch", __func__);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // anon namespace
|
|
|
|
|
|
|
|
|
|
bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
|
|
|
|
|
{
|
|
|
|
@ -1518,7 +1592,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|
|
|
|
CDiskBlockPos pos = pindex->GetUndoPos();
|
|
|
|
|
if (pos.IsNull())
|
|
|
|
|
return error("DisconnectBlock() : no undo data available");
|
|
|
|
|
if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
|
|
|
|
|
if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash()))
|
|
|
|
|
return error("DisconnectBlock() : failure reading undo data");
|
|
|
|
|
|
|
|
|
|
if (blockUndo.vtxundo.size() + 1 != block.vtx.size())
|
|
|
|
@ -1760,7 +1834,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|
|
|
|
CDiskBlockPos pos;
|
|
|
|
|
if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
|
|
|
|
|
return error("ConnectBlock() : FindUndoPos failed");
|
|
|
|
|
if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash()))
|
|
|
|
|
if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash()))
|
|
|
|
|
return state.Abort("Failed to write undo data");
|
|
|
|
|
|
|
|
|
|
// update nUndoPos in block index
|
|
|
|
@ -2926,7 +3000,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
|
|
|
|
CBlockUndo undo;
|
|
|
|
|
CDiskBlockPos pos = pindex->GetUndoPos();
|
|
|
|
|
if (!pos.IsNull()) {
|
|
|
|
|
if (!undo.ReadFromDisk(pos, pindex->pprev->GetBlockHash()))
|
|
|
|
|
if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash()))
|
|
|
|
|
return error("VerifyDB() : *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -4491,61 +4565,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
|
|
|
|
|
{
|
|
|
|
|
// Open history file to append
|
|
|
|
|
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
|
|
|
|
|
if (fileout.IsNull())
|
|
|
|
|
return error("CBlockUndo::WriteToDisk : OpenUndoFile failed");
|
|
|
|
|
|
|
|
|
|
// Write index header
|
|
|
|
|
unsigned int nSize = fileout.GetSerializeSize(*this);
|
|
|
|
|
fileout << FLATDATA(Params().MessageStart()) << nSize;
|
|
|
|
|
|
|
|
|
|
// Write undo data
|
|
|
|
|
long fileOutPos = ftell(fileout.Get());
|
|
|
|
|
if (fileOutPos < 0)
|
|
|
|
|
return error("CBlockUndo::WriteToDisk : ftell failed");
|
|
|
|
|
pos.nPos = (unsigned int)fileOutPos;
|
|
|
|
|
fileout << *this;
|
|
|
|
|
|
|
|
|
|
// calculate & write checksum
|
|
|
|
|
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
|
|
|
|
hasher << hashBlock;
|
|
|
|
|
hasher << *this;
|
|
|
|
|
fileout << hasher.GetHash();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
|
|
|
|
|
{
|
|
|
|
|
// Open history file to read
|
|
|
|
|
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
|
|
|
|
|
if (filein.IsNull())
|
|
|
|
|
return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed");
|
|
|
|
|
|
|
|
|
|
// Read block
|
|
|
|
|
uint256 hashChecksum;
|
|
|
|
|
try {
|
|
|
|
|
filein >> *this;
|
|
|
|
|
filein >> hashChecksum;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& e) {
|
|
|
|
|
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify checksum
|
|
|
|
|
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
|
|
|
|
|
hasher << hashBlock;
|
|
|
|
|
hasher << *this;
|
|
|
|
|
if (hashChecksum != hasher.GetHash())
|
|
|
|
|
return error("CBlockUndo::ReadFromDisk : Checksum mismatch");
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CBlockFileInfo::ToString() const {
|
|
|
|
|
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
|
|
|
|
|
}
|
|
|
|
|