aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp119
1 files changed, 93 insertions, 26 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 9e07f43c44..ddc37ea534 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -23,6 +23,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <boost/thread.hpp>
using namespace std;
using namespace boost;
@@ -643,7 +644,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
// 2. P2SH scripts with a crazy number of expensive
// CHECKSIG/CHECKMULTISIG operations
//
-bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
@@ -716,7 +717,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx)
return nSigOps;
}
-unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs)
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
{
if (tx.IsCoinBase())
return 0;
@@ -1022,7 +1023,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
pool.addUnchecked(hash, entry);
}
- g_signals.SyncTransaction(tx, NULL);
+ SyncWithWallets(tx, NULL);
return true;
}
@@ -1450,7 +1451,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1838,10 +1839,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);
- // Watch for transactions paying to me
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
- g_signals.SyncTransaction(tx, &block);
-
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase);
@@ -1959,15 +1956,19 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
-// Connect a new block to chainActive.
-bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
+// Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
+// corresponding to pindexNew, to bypass loading it again from disk.
+bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) {
assert(pindexNew->pprev == chainActive.Tip());
mempool.check(pcoinsTip);
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
CBlock block;
- if (!ReadBlockFromDisk(block, pindexNew))
- return state.Abort(_("Failed to read block"));
+ if (!pblock) {
+ if (!ReadBlockFromDisk(block, pindexNew))
+ return state.Abort(_("Failed to read block"));
+ pblock = &block;
+ }
// Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3;
@@ -1975,7 +1976,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
{
CCoinsViewCache view(*pcoinsTip, true);
CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
- if (!ConnectBlock(block, state, pindexNew, view)) {
+ if (!ConnectBlock(*pblock, state, pindexNew, view)) {
if (state.IsInvalid())
InvalidBlockFound(pindexNew, state);
return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
@@ -1994,7 +1995,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
// Remove conflicting transactions from the mempool.
list<CTransaction> txConflicted;
- mempool.removeForBlock(block.vtx, pindexNew->nHeight, txConflicted);
+ mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted);
mempool.check(pcoinsTip);
// Update chainActive & related variables.
UpdateTip(pindexNew);
@@ -2004,8 +2005,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
SyncWithWallets(tx, NULL);
}
// ... and about transactions that got confirmed:
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx, &block);
+ BOOST_FOREACH(const CTransaction &tx, pblock->vtx) {
+ SyncWithWallets(tx, pblock);
}
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
@@ -2054,7 +2055,8 @@ static CBlockIndex* FindMostWorkChain() {
}
// Try to make some progress towards making pindexMostWork the active block.
-static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
+// pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
+static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) {
AssertLockHeld(cs_main);
bool fInvalidFound = false;
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -2069,14 +2071,15 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
// Build list of new blocks to connect.
std::vector<CBlockIndex*> vpindexToConnect;
vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1));
- while (pindexMostWork && pindexMostWork != pindexFork) {
- vpindexToConnect.push_back(pindexMostWork);
- pindexMostWork = pindexMostWork->pprev;
+ CBlockIndex *pindexIter = pindexMostWork;
+ while (pindexIter && pindexIter != pindexFork) {
+ vpindexToConnect.push_back(pindexIter);
+ pindexIter = pindexIter->pprev;
}
// Connect new blocks.
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
- if (!ConnectTip(state, pindexConnect)) {
+ if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
@@ -2117,7 +2120,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
return true;
}
-bool ActivateBestChain(CValidationState &state) {
+// Make the best chain active, in multiple steps. The result is either failure
+// or an activated best chain. pblock is either NULL or a pointer to a block
+// that is already loaded (to avoid loading it again from disk).
+bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
CBlockIndex *pindexNewTip = NULL;
CBlockIndex *pindexMostWork = NULL;
do {
@@ -2132,7 +2138,7 @@ bool ActivateBestChain(CValidationState &state) {
if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
return true;
- if (!ActivateBestChainStep(state, pindexMostWork))
+ if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL))
return false;
pindexNewTip = chainActive.Tip();
@@ -2675,7 +2681,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
}
- if (!ActivateBestChain(state))
+ if (!ActivateBestChain(state, pblock))
return error("ProcessBlock() : ActivateBestChain failed");
return true;
@@ -3115,7 +3121,7 @@ bool InitBlockIndex() {
CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
- if (!ActivateBestChain(state))
+ if (!ActivateBestChain(state, &block))
return error("LoadBlockIndex() : genesis block cannot be activated");
} catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
@@ -3213,7 +3219,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
uint64_t nRewind = blkdat.GetPos();
- while (blkdat.good() && !blkdat.eof()) {
+ while (!blkdat.eof()) {
boost::this_thread::interruption_point();
blkdat.SetPos(nRewind);
@@ -4540,7 +4546,68 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
+bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
+{
+ // Open history file to append
+ CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ 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);
+ 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();
+
+ // Flush stdio buffers and commit to disk before returning
+ fflush(fileout);
+ if (!IsInitialBlockDownload())
+ FileCommit(fileout);
+
+ return true;
+}
+
+bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
+{
+ // Open history file to read
+ CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed");
+
+ // Read block
+ uint256 hashChecksum;
+ try {
+ filein >> *this;
+ filein >> hashChecksum;
+ }
+ catch (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).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str());
+ }