/src/main.cpp
C++ | 3856 lines | 2766 code | 606 blank | 484 comment | 737 complexity | b78adddad1430f1ee0e1e9c0bca2f03c MD5 | raw file
Possible License(s): 0BSD, GPL-3.0, MIT
Large files files are truncated, but you can click here to view the full file
- // Copyright (c) 2009-2010 Satoshi Nakamoto
- // Copyright (c) 2009-2012 The Bitcoin developers
- // Copyright (c) 2011-2012 Litecoin Developers
- // Distributed under the MIT/X11 software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- #include "checkpoints.h"
- #include "db.h"
- #include "net.h"
- #include "init.h"
- #include "ui_interface.h"
- #include <boost/algorithm/string/replace.hpp>
- #include <boost/filesystem.hpp>
- #include <boost/filesystem/fstream.hpp>
- using namespace std;
- using namespace boost;
- //
- // Global state
- //
- CCriticalSection cs_setpwalletRegistered;
- set<CWallet*> setpwalletRegistered;
- CCriticalSection cs_main;
- CTxMemPool mempool;
- unsigned int nTransactionsUpdated = 0;
- map<uint256, CBlockIndex*> mapBlockIndex;
- uint256 hashGenesisBlock("0x12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2");
- static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20); // Litecoin: starting difficulty is 1 / 2^12
- CBlockIndex* pindexGenesisBlock = NULL;
- int nBestHeight = -1;
- CBigNum bnBestChainWork = 0;
- CBigNum bnBestInvalidWork = 0;
- uint256 hashBestChain = 0;
- CBlockIndex* pindexBest = NULL;
- int64 nTimeBestReceived = 0;
- CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
- map<uint256, CBlock*> mapOrphanBlocks;
- multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
- map<uint256, CDataStream*> mapOrphanTransactions;
- map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
- // Constant stuff for coinbase transactions we create:
- CScript COINBASE_FLAGS;
- const string strMessageMagic = "Litecoin Signed Message:\n";
- double dHashesPerSec;
- int64 nHPSTimerStart;
- // Settings
- int64 nTransactionFee = 0;
- int64 nMinimumInputValue = CENT / 100;
- //////////////////////////////////////////////////////////////////////////////
- //
- // dispatching functions
- //
- // These functions dispatch to one or all registered wallets
- void RegisterWallet(CWallet* pwalletIn)
- {
- {
- LOCK(cs_setpwalletRegistered);
- setpwalletRegistered.insert(pwalletIn);
- }
- }
- void UnregisterWallet(CWallet* pwalletIn)
- {
- {
- LOCK(cs_setpwalletRegistered);
- setpwalletRegistered.erase(pwalletIn);
- }
- }
- // check whether the passed transaction is from us
- bool static IsFromMe(CTransaction& tx)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- if (pwallet->IsFromMe(tx))
- return true;
- return false;
- }
- // get the wallet transaction with the given hash (if it exists)
- bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- if (pwallet->GetTransaction(hashTx,wtx))
- return true;
- return false;
- }
- // erases transaction with the given hash from all wallets
- void static EraseFromWallets(uint256 hash)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->EraseFromWallet(hash);
- }
- // make sure all wallets know about the given transaction, in the given block
- void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
- }
- // notify wallets about a new best chain
- void static SetBestChain(const CBlockLocator& loc)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->SetBestChain(loc);
- }
- // notify wallets about an updated transaction
- void static UpdatedTransaction(const uint256& hashTx)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->UpdatedTransaction(hashTx);
- }
- // dump all wallets
- void static PrintWallets(const CBlock& block)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->PrintWallet(block);
- }
- // notify wallets about an incoming inventory (for request counts)
- void static Inventory(const uint256& hash)
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->Inventory(hash);
- }
- // ask wallets to resend their transactions
- void static ResendWalletTransactions()
- {
- BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
- pwallet->ResendWalletTransactions();
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // mapOrphanTransactions
- //
- bool AddOrphanTx(const CDataStream& vMsg)
- {
- CTransaction tx;
- CDataStream(vMsg) >> tx;
- uint256 hash = tx.GetHash();
- if (mapOrphanTransactions.count(hash))
- return false;
- CDataStream* pvMsg = new CDataStream(vMsg);
- // Ignore big transactions, to avoid a
- // send-big-orphans memory exhaustion attack. If a peer has a legitimate
- // large transaction with a missing parent then we assume
- // it will rebroadcast it later, after the parent transaction(s)
- // have been mined or received.
- // 10,000 orphans, each of which is at most 5,000 bytes big is
- // at most 500 megabytes of orphans:
- if (pvMsg->size() > 5000)
- {
- printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
- delete pvMsg;
- return false;
- }
- mapOrphanTransactions[hash] = pvMsg;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg));
- printf("stored orphan tx %s (mapsz %u)\n", hash.ToString().substr(0,10).c_str(),
- mapOrphanTransactions.size());
- return true;
- }
- void static EraseOrphanTx(uint256 hash)
- {
- if (!mapOrphanTransactions.count(hash))
- return;
- const CDataStream* pvMsg = mapOrphanTransactions[hash];
- CTransaction tx;
- CDataStream(*pvMsg) >> tx;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
- if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
- mapOrphanTransactionsByPrev.erase(txin.prevout.hash);
- }
- delete pvMsg;
- mapOrphanTransactions.erase(hash);
- }
- unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
- {
- unsigned int nEvicted = 0;
- while (mapOrphanTransactions.size() > nMaxOrphans)
- {
- // Evict a random orphan:
- uint256 randomhash = GetRandHash();
- map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
- if (it == mapOrphanTransactions.end())
- it = mapOrphanTransactions.begin();
- EraseOrphanTx(it->first);
- ++nEvicted;
- }
- return nEvicted;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // CTransaction and CTxIndex
- //
- bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
- {
- SetNull();
- if (!txdb.ReadTxIndex(prevout.hash, txindexRet))
- return false;
- if (!ReadFromDisk(txindexRet.pos))
- return false;
- if (prevout.n >= vout.size())
- {
- SetNull();
- return false;
- }
- return true;
- }
- bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout)
- {
- CTxIndex txindex;
- return ReadFromDisk(txdb, prevout, txindex);
- }
- bool CTransaction::ReadFromDisk(COutPoint prevout)
- {
- CTxDB txdb("r");
- CTxIndex txindex;
- return ReadFromDisk(txdb, prevout, txindex);
- }
- bool CTransaction::IsStandard() const
- {
- if (nVersion > CTransaction::CURRENT_VERSION)
- return false;
- BOOST_FOREACH(const CTxIn& txin, vin)
- {
- // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
- // pay-to-script-hash, which is 3 ~80-byte signatures, 3
- // ~65-byte public keys, plus a few script ops.
- if (txin.scriptSig.size() > 500)
- return false;
- if (!txin.scriptSig.IsPushOnly())
- return false;
- }
- BOOST_FOREACH(const CTxOut& txout, vout)
- if (!::IsStandard(txout.scriptPubKey))
- return false;
- return true;
- }
- //
- // Check transaction inputs, and make sure any
- // pay-to-script-hash transactions are evaluating IsStandard scripts
- //
- // Why bother? To avoid denial-of-service attacks; an attacker
- // can submit a standard HASH... OP_EQUAL transaction,
- // which will get accepted into blocks. The redemption
- // script can be anything; an attacker could use a very
- // expensive-to-check-upon-redemption script like:
- // DUP CHECKSIG DROP ... repeated 100 times... OP_1
- //
- bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
- {
- if (IsCoinBase())
- return true; // Coinbases don't use vin normally
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
- vector<vector<unsigned char> > vSolutions;
- txnouttype whichType;
- // get the scriptPubKey corresponding to this input:
- const CScript& prevScript = prev.scriptPubKey;
- if (!Solver(prevScript, whichType, vSolutions))
- return false;
- int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
- if (nArgsExpected < 0)
- return false;
- // Transactions with extra stuff in their scriptSigs are
- // non-standard. Note that this EvalScript() call will
- // be quick, because if there are any operations
- // beside "push data" in the scriptSig the
- // IsStandard() call returns false
- vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
- return false;
- if (whichType == TX_SCRIPTHASH)
- {
- if (stack.empty())
- return false;
- CScript subscript(stack.back().begin(), stack.back().end());
- vector<vector<unsigned char> > vSolutions2;
- txnouttype whichType2;
- if (!Solver(subscript, whichType2, vSolutions2))
- return false;
- if (whichType2 == TX_SCRIPTHASH)
- return false;
- int tmpExpected;
- tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
- if (tmpExpected < 0)
- return false;
- nArgsExpected += tmpExpected;
- }
- if (stack.size() != (unsigned int)nArgsExpected)
- return false;
- }
- return true;
- }
- unsigned int
- CTransaction::GetLegacySigOpCount() const
- {
- unsigned int nSigOps = 0;
- BOOST_FOREACH(const CTxIn& txin, vin)
- {
- nSigOps += txin.scriptSig.GetSigOpCount(false);
- }
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- nSigOps += txout.scriptPubKey.GetSigOpCount(false);
- }
- return nSigOps;
- }
- int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
- {
- if (fClient)
- {
- if (hashBlock == 0)
- return 0;
- }
- else
- {
- CBlock blockTmp;
- if (pblock == NULL)
- {
- // Load the block this tx is in
- CTxIndex txindex;
- if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
- return 0;
- if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
- return 0;
- pblock = &blockTmp;
- }
- // Update the tx's hashBlock
- hashBlock = pblock->GetHash();
- // Locate the transaction
- for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
- if (pblock->vtx[nIndex] == *(CTransaction*)this)
- break;
- if (nIndex == (int)pblock->vtx.size())
- {
- vMerkleBranch.clear();
- nIndex = -1;
- printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
- return 0;
- }
- // Fill in merkle branch
- vMerkleBranch = pblock->GetMerkleBranch(nIndex);
- }
- // Is the tx in a block that's in the main chain
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi == mapBlockIndex.end())
- return 0;
- CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
- return 0;
- return pindexBest->nHeight - pindex->nHeight + 1;
- }
- bool CTransaction::CheckTransaction() const
- {
- // Basic checks that don't depend on any context
- if (vin.empty())
- return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
- if (vout.empty())
- return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
- // Size limits
- if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
- return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
- // Check for negative or overflow output values
- int64 nValueOut = 0;
- BOOST_FOREACH(const CTxOut& txout, vout)
- {
- if (txout.nValue < 0)
- return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
- if (txout.nValue > MAX_MONEY)
- return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
- nValueOut += txout.nValue;
- if (!MoneyRange(nValueOut))
- return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
- }
- // Check for duplicate inputs
- set<COutPoint> vInOutPoints;
- BOOST_FOREACH(const CTxIn& txin, vin)
- {
- if (vInOutPoints.count(txin.prevout))
- return false;
- vInOutPoints.insert(txin.prevout);
- }
- if (IsCoinBase())
- {
- if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
- }
- else
- {
- BOOST_FOREACH(const CTxIn& txin, vin)
- if (txin.prevout.IsNull())
- return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
- }
- return true;
- }
- bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
- bool* pfMissingInputs)
- {
- if (pfMissingInputs)
- *pfMissingInputs = false;
- if (!tx.CheckTransaction())
- return error("CTxMemPool::accept() : CheckTransaction failed");
- // Coinbase is only valid in a block, not as a loose transaction
- if (tx.IsCoinBase())
- return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
- // To help v0.1.5 clients who would see it as a negative number
- if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
- return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
- // Rather not work on nonstandard transactions (unless -testnet)
- if (!fTestNet && !tx.IsStandard())
- return error("CTxMemPool::accept() : nonstandard transaction type");
- // Do we already have it?
- uint256 hash = tx.GetHash();
- {
- LOCK(cs);
- if (mapTx.count(hash))
- return false;
- }
- if (fCheckInputs)
- if (txdb.ContainsTx(hash))
- return false;
- // Check for conflicts with in-memory transactions
- CTransaction* ptxOld = NULL;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- COutPoint outpoint = tx.vin[i].prevout;
- if (mapNextTx.count(outpoint))
- {
- // Disable replacement feature for now
- return false;
- // Allow replacing with a newer version of the same transaction
- if (i != 0)
- return false;
- ptxOld = mapNextTx[outpoint].ptx;
- if (ptxOld->IsFinal())
- return false;
- if (!tx.IsNewerThan(*ptxOld))
- return false;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- COutPoint outpoint = tx.vin[i].prevout;
- if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
- return false;
- }
- break;
- }
- }
- if (fCheckInputs)
- {
- MapPrevTx mapInputs;
- map<uint256, CTxIndex> mapUnused;
- bool fInvalid = false;
- if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
- {
- if (fInvalid)
- return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
- if (pfMissingInputs)
- *pfMissingInputs = true;
- return false;
- }
- // Check for non-standard pay-to-script-hash in inputs
- if (!tx.AreInputsStandard(mapInputs) && !fTestNet)
- return error("CTxMemPool::accept() : nonstandard transaction input");
- // Note: if you modify this code to accept non-standard transactions, then
- // you should add code here to check that the transaction does a
- // reasonable number of ECDSA signature verifications.
- int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
- unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
- // Don't accept it if it can't get into a block
- int64 txMinFee = tx.GetMinFee(1000, true, GMF_RELAY);
- if (nFees < txMinFee)
- return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d,
- hash.ToString().c_str(),
- nFees, txMinFee);
- // Continuously rate-limit free transactions
- // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
- // be annoying or make other's transactions take longer to confirm.
- if (nFees < MIN_RELAY_TX_FEE)
- {
- static CCriticalSection cs;
- static double dFreeCount;
- static int64 nLastTime;
- int64 nNow = GetTime();
- {
- LOCK(cs);
- // Use an exponentially decaying ~10-minute window:
- dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
- nLastTime = nNow;
- // -limitfreerelay unit is thousand-bytes-per-minute
- // At default rate it would take over a month to fill 1GB
- if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
- return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
- if (fDebug)
- printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
- dFreeCount += nSize;
- }
- }
- // Check against previous transactions
- // This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
- {
- return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
- }
- }
- // Store transaction in memory
- {
- LOCK(cs);
- if (ptxOld)
- {
- printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
- remove(*ptxOld);
- }
- addUnchecked(hash, tx);
- }
- ///// are we sure this is ok when loading transactions or restoring block txes
- // If updated, erase old tx from wallet
- if (ptxOld)
- EraseFromWallets(ptxOld->GetHash());
- printf("CTxMemPool::accept() : accepted %s (poolsz %u)\n",
- hash.ToString().c_str(),
- mapTx.size());
- return true;
- }
- bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
- {
- return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
- }
- bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
- {
- // Add to memory pool without checking anything. Don't call this directly,
- // call CTxMemPool::accept to properly check the transaction first.
- {
- mapTx[hash] = tx;
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
- nTransactionsUpdated++;
- }
- return true;
- }
- bool CTxMemPool::remove(CTransaction &tx)
- {
- // Remove transaction from memory pool
- {
- LOCK(cs);
- uint256 hash = tx.GetHash();
- if (mapTx.count(hash))
- {
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- mapNextTx.erase(txin.prevout);
- mapTx.erase(hash);
- nTransactionsUpdated++;
- }
- }
- return true;
- }
- void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
- {
- vtxid.clear();
- LOCK(cs);
- vtxid.reserve(mapTx.size());
- for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
- vtxid.push_back((*mi).first);
- }
- int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
- {
- if (hashBlock == 0 || nIndex == -1)
- return 0;
- // Find the block it claims to be in
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi == mapBlockIndex.end())
- return 0;
- CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
- return 0;
- // Make sure the merkle branch connects to this block
- if (!fMerkleVerified)
- {
- if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
- return 0;
- fMerkleVerified = true;
- }
- pindexRet = pindex;
- return pindexBest->nHeight - pindex->nHeight + 1;
- }
- int CMerkleTx::GetBlocksToMaturity() const
- {
- if (!IsCoinBase())
- return 0;
- return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
- }
- bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
- {
- if (fClient)
- {
- if (!IsInMainChain() && !ClientConnectInputs())
- return false;
- return CTransaction::AcceptToMemoryPool(txdb, false);
- }
- else
- {
- return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
- }
- }
- bool CMerkleTx::AcceptToMemoryPool()
- {
- CTxDB txdb("r");
- return AcceptToMemoryPool(txdb);
- }
- bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
- {
- {
- LOCK(mempool.cs);
- // Add previous supporting transactions first
- BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
- {
- if (!tx.IsCoinBase())
- {
- uint256 hash = tx.GetHash();
- if (!mempool.exists(hash) && !txdb.ContainsTx(hash))
- tx.AcceptToMemoryPool(txdb, fCheckInputs);
- }
- }
- return AcceptToMemoryPool(txdb, fCheckInputs);
- }
- return false;
- }
- bool CWalletTx::AcceptWalletTransaction()
- {
- CTxDB txdb("r");
- return AcceptWalletTransaction(txdb);
- }
- int CTxIndex::GetDepthInMainChain() const
- {
- // Read block header
- CBlock block;
- if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false))
- return 0;
- // Find the block in the index
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.GetHash());
- if (mi == mapBlockIndex.end())
- return 0;
- CBlockIndex* pindex = (*mi).second;
- if (!pindex || !pindex->IsInMainChain())
- return 0;
- return 1 + nBestHeight - pindex->nHeight;
- }
- // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
- bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock)
- {
- {
- LOCK(cs_main);
- {
- LOCK(mempool.cs);
- if (mempool.exists(hash))
- {
- tx = mempool.lookup(hash);
- return true;
- }
- }
- CTxDB txdb("r");
- CTxIndex txindex;
- if (tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex))
- {
- CBlock block;
- if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
- hashBlock = block.GetHash();
- return true;
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // CBlock and CBlockIndex
- //
- bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
- {
- if (!fReadTransactions)
- {
- *this = pindex->GetBlockHeader();
- return true;
- }
- if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions))
- return false;
- if (GetHash() != pindex->GetBlockHash())
- return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
- return true;
- }
- uint256 static GetOrphanRoot(const CBlock* pblock)
- {
- // Work back to the first block in the orphan chain
- while (mapOrphanBlocks.count(pblock->hashPrevBlock))
- pblock = mapOrphanBlocks[pblock->hashPrevBlock];
- return pblock->GetHash();
- }
- int64 static GetBlockValue(int nHeight, int64 nFees)
- {
- int64 nSubsidy = 50 * COIN;
- // Subsidy is cut in half every 840000 blocks, which will occur approximately every 4 years
- nSubsidy >>= (nHeight / 840000); // Litecoin: 840k blocks in ~4 years
- return nSubsidy + nFees;
- }
- static const int64 nTargetTimespan = 3.5 * 24 * 60 * 60; // Litecoin: 3.5 days
- static const int64 nTargetSpacing = 2.5 * 60; // Litecoin: 2.5 minutes
- static const int64 nInterval = nTargetTimespan / nTargetSpacing;
- //
- // minimum amount of work that could possibly be required nTime after
- // minimum work required was nBase
- //
- unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
- {
- // Testnet has min-difficulty blocks
- // after nTargetSpacing*2 time between blocks:
- if (fTestNet && nTime > nTargetSpacing*2)
- return bnProofOfWorkLimit.GetCompact();
- CBigNum bnResult;
- bnResult.SetCompact(nBase);
- while (nTime > 0 && bnResult < bnProofOfWorkLimit)
- {
- // Maximum 400% adjustment...
- bnResult *= 4;
- // ... in best-case exactly 4-times-normal target time
- nTime -= nTargetTimespan*4;
- }
- if (bnResult > bnProofOfWorkLimit)
- bnResult = bnProofOfWorkLimit;
- return bnResult.GetCompact();
- }
- unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock)
- {
- unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();
- // Genesis block
- if (pindexLast == NULL)
- return nProofOfWorkLimit;
- // Only change once per interval
- if ((pindexLast->nHeight+1) % nInterval != 0)
- {
- // Special difficulty rule for testnet:
- if (fTestNet)
- {
- // If the new block's timestamp is more than 2* 10 minutes
- // then allow mining of a min-difficulty block.
- if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2)
- return nProofOfWorkLimit;
- else
- {
- // Return the last non-special-min-difficulty-rules-block
- const CBlockIndex* pindex = pindexLast;
- while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit)
- pindex = pindex->pprev;
- return pindex->nBits;
- }
- }
- return pindexLast->nBits;
- }
- // Litecoin: This fixes an issue where a 51% attack can change difficulty at will.
- // Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz
- int blockstogoback = nInterval-1;
- if ((pindexLast->nHeight+1) != nInterval)
- blockstogoback = nInterval;
- // Go back by what we want to be 14 days worth of blocks
- const CBlockIndex* pindexFirst = pindexLast;
- for (int i = 0; pindexFirst && i < blockstogoback; i++)
- pindexFirst = pindexFirst->pprev;
- assert(pindexFirst);
- // Limit adjustment step
- int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
- printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
- if (nActualTimespan < nTargetTimespan/4)
- nActualTimespan = nTargetTimespan/4;
- if (nActualTimespan > nTargetTimespan*4)
- nActualTimespan = nTargetTimespan*4;
- // Retarget
- CBigNum bnNew;
- bnNew.SetCompact(pindexLast->nBits);
- bnNew *= nActualTimespan;
- bnNew /= nTargetTimespan;
- if (bnNew > bnProofOfWorkLimit)
- bnNew = bnProofOfWorkLimit;
- /// debug print
- printf("GetNextWorkRequired RETARGET\n");
- printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
- printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
- printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
- return bnNew.GetCompact();
- }
- bool CheckProofOfWork(uint256 hash, unsigned int nBits)
- {
- CBigNum bnTarget;
- bnTarget.SetCompact(nBits);
- // Check range
- if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit)
- return error("CheckProofOfWork() : nBits below minimum work");
- // Check proof of work matches claimed amount
- if (hash > bnTarget.getuint256())
- return error("CheckProofOfWork() : hash doesn't match nBits");
- return true;
- }
- // Return maximum amount of blocks that other nodes claim to have
- int GetNumBlocksOfPeers()
- {
- return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
- }
- bool IsInitialBlockDownload()
- {
- if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
- return true;
- static int64 nLastUpdate;
- static CBlockIndex* pindexLastBest;
- if (pindexBest != pindexLastBest)
- {
- pindexLastBest = pindexBest;
- nLastUpdate = GetTime();
- }
- return (GetTime() - nLastUpdate < 10 &&
- pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
- }
- void static InvalidChainFound(CBlockIndex* pindexNew)
- {
- if (pindexNew->bnChainWork > bnBestInvalidWork)
- {
- bnBestInvalidWork = pindexNew->bnChainWork;
- CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
- uiInterface.NotifyBlocksChanged();
- }
- printf("InvalidChainFound: invalid block=%s height=%d work=%s date=%s\n",
- pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight,
- pindexNew->bnChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S",
- pindexNew->GetBlockTime()).c_str());
- printf("InvalidChainFound: current best=%s height=%d work=%s date=%s\n",
- hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(),
- DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
- if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
- printf("InvalidChainFound: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
- }
- void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
- {
- nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
- // Updating time can change work required on testnet:
- if (fTestNet)
- nBits = GetNextWorkRequired(pindexPrev, this);
- }
- bool CTransaction::DisconnectInputs(CTxDB& txdb)
- {
- // Relinquish previous transactions' spent pointers
- if (!IsCoinBase())
- {
- BOOST_FOREACH(const CTxIn& txin, vin)
- {
- COutPoint prevout = txin.prevout;
- // Get prev txindex from disk
- CTxIndex txindex;
- if (!txdb.ReadTxIndex(prevout.hash, txindex))
- return error("DisconnectInputs() : ReadTxIndex failed");
- if (prevout.n >= txindex.vSpent.size())
- return error("DisconnectInputs() : prevout.n out of range");
- // Mark outpoint as not spent
- txindex.vSpent[prevout.n].SetNull();
- // Write back
- if (!txdb.UpdateTxIndex(prevout.hash, txindex))
- return error("DisconnectInputs() : UpdateTxIndex failed");
- }
- }
- // Remove transaction from index
- // This can fail if a duplicate of this transaction was in a chain that got
- // reorganized away. This is only possible if this transaction was completely
- // spent, so erasing it would be a no-op anway.
- txdb.EraseTxIndex(*this);
- return true;
- }
- bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
- bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid)
- {
- // FetchInputs can return false either because we just haven't seen some inputs
- // (in which case the transaction should be stored as an orphan)
- // or because the transaction is malformed (in which case the transaction should
- // be dropped). If tx is definitely invalid, fInvalid will be set to true.
- fInvalid = false;
- if (IsCoinBase())
- return true; // Coinbase transactions have no inputs to fetch.
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- COutPoint prevout = vin[i].prevout;
- if (inputsRet.count(prevout.hash))
- continue; // Got it already
- // Read txindex
- CTxIndex& txindex = inputsRet[prevout.hash].first;
- bool fFound = true;
- if ((fBlock || fMiner) && mapTestPool.count(prevout.hash))
- {
- // Get txindex from current proposed changes
- txindex = mapTestPool.find(prevout.hash)->second;
- }
- else
- {
- // Read txindex from txdb
- fFound = txdb.ReadTxIndex(prevout.hash, txindex);
- }
- if (!fFound && (fBlock || fMiner))
- return fMiner ? false : error("FetchInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
- // Read txPrev
- CTransaction& txPrev = inputsRet[prevout.hash].second;
- if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
- {
- // Get prev tx from single transactions in memory
- {
- LOCK(mempool.cs);
- if (!mempool.exists(prevout.hash))
- return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
- txPrev = mempool.lookup(prevout.hash);
- }
- if (!fFound)
- txindex.vSpent.resize(txPrev.vout.size());
- }
- else
- {
- // Get prev tx from disk
- if (!txPrev.ReadFromDisk(txindex.pos))
- return error("FetchInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
- }
- }
- // Make sure all prevout.n's are valid:
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- const COutPoint prevout = vin[i].prevout;
- assert(inputsRet.count(prevout.hash) != 0);
- const CTxIndex& txindex = inputsRet[prevout.hash].first;
- const CTransaction& txPrev = inputsRet[prevout.hash].second;
- if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
- {
- // Revisit this if/when transaction replacement is implemented and allows
- // adding inputs:
- fInvalid = true;
- return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
- }
- }
- return true;
- }
- const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const
- {
- MapPrevTx::const_iterator mi = inputs.find(input.prevout.hash);
- if (mi == inputs.end())
- throw std::runtime_error("CTransaction::GetOutputFor() : prevout.hash not found");
- const CTransaction& txPrev = (mi->second).second;
- if (input.prevout.n >= txPrev.vout.size())
- throw std::runtime_error("CTransaction::GetOutputFor() : prevout.n out of range");
- return txPrev.vout[input.prevout.n];
- }
- int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
- {
- if (IsCoinBase())
- return 0;
- int64 nResult = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- nResult += GetOutputFor(vin[i], inputs).nValue;
- }
- return nResult;
- }
- unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
- {
- if (IsCoinBase())
- return 0;
- unsigned int nSigOps = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- const CTxOut& prevout = GetOutputFor(vin[i], inputs);
- if (prevout.scriptPubKey.IsPayToScriptHash())
- nSigOps += prevout.scriptPubKey.GetSigOpCount(vin[i].scriptSig);
- }
- return nSigOps;
- }
- bool CTransaction::ConnectInputs(MapPrevTx inputs,
- map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
- const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash)
- {
- // Take over previous transactions' spent pointers
- // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
- // fMiner is true when called from the internal litecoin miner
- // ... both are false when called from CTransaction::AcceptToMemoryPool
- if (!IsCoinBase())
- {
- int64 nValueIn = 0;
- int64 nFees = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- COutPoint prevout = vin[i].prevout;
- assert(inputs.count(prevout.hash) > 0);
- CTxIndex& txindex = inputs[prevout.hash].first;
- CTransaction& txPrev = inputs[prevout.hash].second;
- if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
- return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
- // If prev is coinbase, check that it's matured
- if (txPrev.IsCoinBase())
- for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev)
- if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
- return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
- // Check for negative or overflow input values
- nValueIn += txPrev.vout[prevout.n].nValue;
- if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return DoS(100, error("ConnectInputs() : txin values out of range"));
- }
- // The first loop above does all the inexpensive checks.
- // Only if ALL inputs pass do we perform expensive ECDSA signature checks.
- // Helps prevent CPU exhaustion attacks.
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- COutPoint prevout = vin[i].prevout;
- assert(inputs.count(prevout.hash) > 0);
- CTxIndex& txindex = inputs[prevout.hash].first;
- CTransaction& txPrev = inputs[prevout.hash].second;
- // Check for conflicts (double-spend)
- // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
- // for an attacker to attempt to split the network.
- if (!txindex.vSpent[prevout.n].IsNull())
- return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
- // Skip ECDSA signature verification when connecting blocks (fBlock=true)
- // before the last blockchain checkpoint. This is safe because block merkle hashes are
- // still computed and checked, and any change will be caught at the next checkpoint.
- if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
- {
- // Verify signature
- if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
- {
- // only during transition phase for P2SH: do not invoke anti-DoS code for
- // potentially old clients relaying bad P2SH transactions
- if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0))
- return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
- return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
- }
- }
- // Mark outpoints as spent
- txindex.vSpent[prevout.n] = posThisTx;
- // Write back
- if (fBlock || fMiner)
- {
- mapTestPool[prevout.hash] = txindex;
- }
- }
- if (nValueIn < GetValueOut())
- return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
- // Tally transaction fees
- int64 nTxFee = nValueIn - GetValueOut();
- if (nTxFee < 0)
- return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
- nFees += nTxFee;
- if (!MoneyRange(nFees))
- return DoS(100, error("ConnectInputs() : nFees out of range"));
- }
- return true;
- }
- bool CTransaction::ClientConnectInputs()
- {
- if (IsCoinBase())
- return false;
- // Take over previous transactions' spent pointers
- {
- LOCK(mempool.cs);
- int64 nValueIn = 0;
- for (unsigned int i = 0; i < vin.size(); i++)
- {
- // Get prev tx from single transactions in memory
- COutPoint prevout = vin[i].prevout;
- if (!mempool.exists(prevout.hash))
- return false;
- CTransaction& txPrev = mempool.lookup(prevout.hash);
- if (prevout.n >= txPrev.vout.size())
- return false;
- // Verify signature
- if (!VerifySignature(txPrev, *this, i, true, 0))
- return error("ConnectInputs() : VerifySignature failed");
- ///// this is redundant with the mempool.mapNextTx stuff,
- ///// not sure which I want to get rid of
- ///// this has to go away now that posNext is gone
- // // Check for conflicts
- // if (!txPrev.vout[prevout.n].posNext.IsNull())
- // return error("ConnectInputs() : prev tx already used");
- //
- // // Flag outpoints as used
- // txPrev.vout[prevout.n].posNext = posThisTx;
- nValueIn += txPrev.vout[prevout.n].nValue;
- if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return error("ClientConnectInputs() : txin values out of range");
- }
- if (GetValueOut() > nValueIn)
- return false;
- }
- return true;
- }
- bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
- {
- // Disconnect in reverse order
- for (int i = vtx.size()-1; i >= 0; i--)
- if (!vtx[i].DisconnectInputs(txdb))
- return false;
- // Update block index on disk without changing it in memory.
- // The memory index structure will be changed after the db commits.
- if (pindex->pprev)
- {
- CDiskBlockIndex blockindexPrev(pindex->pprev);
- blockindexPrev.hashNext = 0;
- if (!txdb.WriteBlockIndex(blockindexPrev))
- return error("DisconnectBlock() : WriteBlockIndex failed");
- }
- return true;
- }
- bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
- {
- // Check it again in case a previous version let a bad block in
- if (!CheckBlock())
- return false;
- // Do not allow blocks that contain transactions which 'overwrite' older transactions,
- // unless those are already completely spent.
- // If such overwrites are allowed, coinbases and transactions depending upon those
- // can be duplicated to remove the ability to spend the first instance -- even after
- // being sent to another address.
- // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.
- // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
- // already refuses previously-known transaction id's entirely.
- // This rule applies to all blocks whose timestamp is after October 1, 2012, 0:00 UTC.
- int64 nBIP30SwitchTime = 1349049600;
- bool fEnforceBIP30 = (pindex->nTime > nBIP30SwitchTime);
- // BIP16 didn't become active until October 1 2012
- int64 nBIP16SwitchTime = 1349049600;
- bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
- //// issue here: it doesn't know the version
- unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size());
- map<uint256, CTxIndex> mapQueuedChanges;
- int64 nFees = 0;
- unsigned int nSigOps = 0;
- BOOST_FOREACH(CTransaction& tx, vtx)
- {
- uint256 hashTx = tx.GetHash();
- if (fEnforceBIP30) {
- CTxIndex txindexOld;
- if (txdb.ReadTxIndex(hashTx, txindexOld)) {
- BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent)
- if (pos.IsNull())
- return false;
- }
- }
- nSigOps += tx.GetLegacySigOpCount();
- if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("ConnectBlock() : too many sigops"));
- CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
- nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
- MapPrevTx mapInputs;
- if (!tx.IsCoinBase())
- {
- bool fInvalid;
- if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
- return false;
- if (fStrictPayToScriptHash)
- {
- // Add in sigops done by pay-to-script-hash inputs;
- // this is to prevent a "rogue miner" from creating
- // an incredibly-expensive-to-validate block.
- nSigOps += tx.GetP2SHSigOpCount(mapInputs);
- if (nSigOps > MAX_BLOCK_SIGOPS)
- return DoS(100, error("ConnectBlock() : too many sigops"));
- }
- nFees += tx.GetValueIn(mapInputs)-tx.GetValueOut();
- if (!tx.ConnectInputs(mapInputs, mapQueuedChanges, posThisTx, pindex, true, false, fStrictPayToScriptHash))
- return false;
- }
- mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size());
- }
- // Write queued txindex changes
- for (map<uint256, CTxIndex>::iterator mi = mapQueuedChanges.begin(); mi != mapQueuedChanges.end(); ++mi)
- {
- if (!txdb.UpdateTxIndex((*mi).first, (*mi).second))
- return error("ConnectBlock() : UpdateTxIndex failed");
- }
- if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
- return false;
- // Update block index on disk without changing it in memory.
- // The memory index structure will be changed after the db commits.
- if (pindex->pprev)
- {
- CDiskBlockIndex blockindexPrev(pindex->pprev);
- blockindexPrev.hashNext = pindex->GetBlockHash();
- if (!txdb.WriteBlockIndex(blockindexPrev))
- return error("ConnectBlock() : WriteBlockIndex failed");
- }
- // Watch for transactions paying to me
- BOOST_FOREACH(CTransaction& tx, vtx)
- SyncWithWallets(tx, this, true);
- return true;
- }
- bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
- {
- printf("REORGANIZE\n");
- // Find the fork
- CBlockIndex* pfork = pindexBest;
- CBlockIndex* plonger = pindexNew;
- while (pfork != plonger)
- {
- while (plonger->nHeight > pfork->nHeight)
- if (!(plonger = plonger->pprev))
- return error("Reorganize() : plonger->pprev is null");
- if (pfork == plonger)
- break;
- if (!(pfork = pfork->pprev))
- return error("Reorganize() : pfork->pprev is null");
- }
- // List of what to disconnect
- vector<CBlockIndex*> vDisconnect;
- for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev)
- vDisconnect.push_back(pindex);
- // List of what to connect
- vector<CBlockIndex*> vConnect;
- for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev)
- vConnect.push_back(pindex);
- reverse(vConnect.begin(), vConnect.end());
- printf("REORGANIZE: Disconnect %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
- printf("REORGANIZE: Connect %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
- // Disconnect shorter branch
- vector<CTransaction> vResurrect;
- BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
- {
- CBlock block;
- if (!block.ReadFromDisk(pindex))
- return error("Reorganize() : ReadFromDisk for disconnect failed");
- if (!block.DisconnectBlock(txdb, pindex))
- return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
- // Queue memory transactions to resurrect
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
- if (!tx.IsCoinBase())
- vResurrect.push_back(tx);
- }
- // Connect longer branch
- vector<CTransaction> vDelete;
- for (unsigned int i = 0; i < vConnect.size(); i++)
- {
- CBlockIndex* pindex = vConnect[i];
- CBlock block;
- if (!block.ReadFromDisk(pindex))
- return error("Reorganize(…
Large files files are truncated, but you can click here to view the full file