diff options
Diffstat (limited to 'src/main.h')
-rw-r--r-- | src/main.h | 435 |
1 files changed, 130 insertions, 305 deletions
diff --git a/src/main.h b/src/main.h index 95c755221f..b02aa60665 100644 --- a/src/main.h +++ b/src/main.h @@ -2,6 +2,7 @@ // Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef BITCOIN_MAIN_H #define BITCOIN_MAIN_H @@ -9,25 +10,28 @@ #include "bitcoin-config.h" #endif -#include "core.h" #include "bignum.h" -#include "sync.h" +#include "chainparams.h" +#include "coins.h" +#include "core.h" #include "net.h" #include "script.h" +#include "sync.h" +#include "txmempool.h" +#include "uint256.h" + +#include <algorithm> +#include <exception> +#include <map> +#include <set> +#include <stdint.h> +#include <string> +#include <utility> +#include <vector> -#include <list> - -class CWallet; -class CBlock; class CBlockIndex; -class CKeyItem; -class CReserveKey; - -class CAddress; +class CBloomFilter; class CInv; -class CNode; - -struct CBlockIndexWorkComparator; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 1000000; @@ -45,11 +49,9 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB -/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ -static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; /** No amount larger than this (in satoshi) is valid */ -static const int64 MAX_MONEY = 21000000 * COIN; -inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } +static const int64_t MAX_MONEY = 21000000 * COIN; +inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; /** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */ @@ -64,6 +66,16 @@ static const int fHaveUPnP = true; static const int fHaveUPnP = false; #endif +/** "reject" message codes **/ +static const unsigned char REJECT_MALFORMED = 0x01; +static const unsigned char REJECT_INVALID = 0x10; +static const unsigned char REJECT_OBSOLETE = 0x11; +static const unsigned char REJECT_DUPLICATE = 0x12; +static const unsigned char REJECT_NONSTANDARD = 0x40; +static const unsigned char REJECT_DUST = 0x41; +static const unsigned char REJECT_INSUFFICIENTFEE = 0x42; +static const unsigned char REJECT_CHECKPOINT = 0x43; + extern CScript COINBASE_FLAGS; @@ -73,22 +85,12 @@ extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; +extern CTxMemPool mempool; extern std::map<uint256, CBlockIndex*> mapBlockIndex; -extern std::vector<CBlockIndex*> vBlockIndexByHeight; -extern std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; -extern CBlockIndex* pindexGenesisBlock; -extern int nBestHeight; -extern uint256 nBestChainWork; -extern uint256 nBestInvalidWork; -extern uint256 hashBestChain; -extern CBlockIndex* pindexBest; -extern unsigned int nTransactionsUpdated; -extern uint64 nLastBlockTx; -extern uint64 nLastBlockSize; +extern uint64_t nLastBlockTx; +extern uint64_t nLastBlockSize; extern const std::string strMessageMagic; -extern int64 nTimeBestReceived; -extern CCriticalSection cs_setpwalletRegistered; -extern std::set<CWallet*> setpwalletRegistered; +extern int64_t nTimeBestReceived; extern bool fImporting; extern bool fReindex; extern bool fBenchmark; @@ -98,33 +100,30 @@ extern unsigned int nCoinCacheSize; extern bool fHaveGUI; // Settings -extern int64 nTransactionFee; +extern int64_t nTransactionFee; // Minimum disk space required - used in CheckDiskSpace() -static const uint64 nMinDiskSpace = 52428800; +static const uint64_t nMinDiskSpace = 52428800; -class CReserveKey; class CCoinsDB; class CBlockTreeDB; struct CDiskBlockPos; -class CCoins; class CTxUndo; -class CCoinsView; -class CCoinsViewCache; class CScriptCheck; class CValidationState; +class CWalletInterface; struct CBlockTemplate; /** Register a wallet to receive updates from core */ -void RegisterWallet(CWallet* pwalletIn); +void RegisterWallet(CWalletInterface* pwalletIn); /** Unregister a wallet from core */ -void UnregisterWallet(CWallet* pwalletIn); +void UnregisterWallet(CWalletInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllWallets(); /** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); +void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL); /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); @@ -136,7 +135,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd); /** Process an incoming block */ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); /** Check whether enough disk space is available for an incoming block */ -bool CheckDiskSpace(uint64 nAdditionalBytes = 0); +bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); /** Open an undo file (rev?????.dat) */ @@ -153,8 +152,6 @@ void UnloadBlockIndex(); bool VerifyDB(int nCheckLevel, int nCheckDepth); /** Print the loaded block tree */ void PrintBlockTree(); -/** Find a block by height in the currently-connected chain */ -CBlockIndex* FindBlockByHeight(int nHeight); /** Process protocol messages received from a given node */ bool ProcessMessages(CNode* pfrom); /** Send queued protocol messages to be sent to a give node */ @@ -164,7 +161,7 @@ void ThreadScriptCheck(); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); /** Calculate the minimum amount of work a received block needs, without knowing its direct parent */ -unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); +unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime); /** Get the number of active peers */ int GetNumBlocksOfPeers(); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ @@ -177,7 +174,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew); /** Find the best known block, and make it the tip of the block chain */ bool ConnectBestBlock(CValidationState &state); -int64 GetBlockValue(int nHeight, int64 nFees); +int64_t GetBlockValue(int nHeight, int64_t nFees); unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock); void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); @@ -189,6 +186,9 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in /** Abort with a message */ bool AbortNode(const std::string &msg); +/** (try to) add transaction to memory pool **/ +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, + bool* pfMissingInputs, bool fRejectInsaneFee=false); @@ -197,10 +197,6 @@ bool AbortNode(const std::string &msg); - - -bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); - struct CDiskBlockPos { int nFile; @@ -262,7 +258,7 @@ enum GetMinFee_mode GMF_SEND, }; -int64 GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode); +int64_t GetMinFee(const CTransaction& tx, bool fAllowFree, enum GetMinFee_mode mode); // // Check transaction inputs, and make sure any @@ -322,12 +318,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state); */ bool IsStandardTx(const CTransaction& tx, std::string& reason); -bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0); +bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0); /** Amount of bitcoins spent by the transaction. @return sum of all outputs (note: does not include fees) */ -int64 GetValueOut(const CTransaction& tx); +int64_t GetValueOut(const CTransaction& tx); /** Undo information for a CBlock */ class CBlockUndo @@ -615,8 +611,8 @@ public: unsigned int nUndoSize; // number of used bytes in the undo file unsigned int nHeightFirst; // lowest height of block in file unsigned int nHeightLast; // highest height of block in file - uint64 nTimeFirst; // earliest time of block in file - uint64 nTimeLast; // latest time of block in file + uint64_t nTimeFirst; // earliest time of block in file + uint64_t nTimeLast; // latest time of block in file IMPLEMENT_SERIALIZE( READWRITE(VARINT(nBlocks)); @@ -647,7 +643,7 @@ public: } // update statistics (does not update nSize) - void AddBlock(unsigned int nHeightIn, uint64 nTimeIn) { + void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { if (nBlocks==0 || nHeightFirst > nHeightIn) nHeightFirst = nHeightIn; if (nBlocks==0 || nTimeFirst > nTimeIn) @@ -660,10 +656,6 @@ public: } }; -extern CCriticalSection cs_LastBlockFile; -extern CBlockFileInfo infoLastBlockFile; -extern int nLastBlockFile; - enum BlockStatus { BLOCK_VALID_UNKNOWN = 0, BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future @@ -805,9 +797,9 @@ public: return *phashBlock; } - int64 GetBlockTime() const + int64_t GetBlockTime() const { - return (int64)nTime; + return (int64_t)nTime; } CBigNum GetBlockWork() const @@ -819,15 +811,6 @@ public: return (CBigNum(1)<<256) / (bnTarget+1); } - bool IsInMainChain() const - { - return nHeight < (int)vBlockIndexByHeight.size() && vBlockIndexByHeight[nHeight] == this; - } - - CBlockIndex *GetNextInMainChain() const { - return nHeight+1 >= (int)vBlockIndexByHeight.size() ? NULL : vBlockIndexByHeight[nHeight+1]; - } - bool CheckIndex() const { return CheckProofOfWork(GetBlockHash(), nBits); @@ -835,11 +818,11 @@ public: enum { nMedianTimeSpan=11 }; - int64 GetMedianTimePast() const + int64_t GetMedianTimePast() const { - int64 pmedian[nMedianTimeSpan]; - int64* pbegin = &pmedian[nMedianTimeSpan]; - int64* pend = &pmedian[nMedianTimeSpan]; + int64_t pmedian[nMedianTimeSpan]; + int64_t* pbegin = &pmedian[nMedianTimeSpan]; + int64_t* pend = &pmedian[nMedianTimeSpan]; const CBlockIndex* pindex = this; for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) @@ -849,17 +832,7 @@ public: return pbegin[(pend - pbegin)/2]; } - int64 GetMedianTime() const - { - const CBlockIndex* pindex = this; - for (int i = 0; i < nMedianTimeSpan/2; i++) - { - if (!pindex->GetNextInMainChain()) - return GetBlockTime(); - pindex = pindex->GetNextInMainChain(); - } - return pindex->GetMedianTimePast(); - } + int64_t GetMedianTime() const; /** * Returns true if there are nRequired or more blocks of minVersion or above @@ -870,8 +843,8 @@ public: std::string ToString() const { - return strprintf("CBlockIndex(pprev=%p, pnext=%p, nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, GetNextInMainChain(), nHeight, + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", + pprev, nHeight, hashMerkleRoot.ToString().c_str(), GetBlockHash().ToString().c_str()); } @@ -882,19 +855,6 @@ public: } }; -struct CBlockIndexWorkComparator -{ - bool operator()(CBlockIndex *pa, CBlockIndex *pb) { - if (pa->nChainWork > pb->nChainWork) return false; - if (pa->nChainWork < pb->nChainWork) return true; - - if (pa->GetBlockHash() < pb->GetBlockHash()) return false; - if (pa->GetBlockHash() > pb->GetBlockHash()) return true; - - return false; // identical blocks - } -}; - /** Used to marshal pointers into hashes for db storage. */ @@ -973,17 +933,26 @@ private: MODE_ERROR, // run-time error } mode; int nDoS; + std::string strRejectReason; + unsigned char chRejectCode; + bool corruptionPossible; public: CValidationState() : mode(MODE_VALID), nDoS(0) {} - bool DoS(int level, bool ret = false) { + bool DoS(int level, bool ret = false, + unsigned char chRejectCodeIn=0, std::string strRejectReasonIn="", + bool corruptionIn=false) { + chRejectCode = chRejectCodeIn; + strRejectReason = strRejectReasonIn; + corruptionPossible = corruptionIn; if (mode == MODE_ERROR) return ret; nDoS += level; mode = MODE_INVALID; return ret; } - bool Invalid(bool ret = false) { - return DoS(0, ret); + bool Invalid(bool ret = false, + unsigned char _chRejectCode=0, std::string _strRejectReason="") { + return DoS(0, ret, _chRejectCode, _strRejectReason); } bool Error() { mode = MODE_ERROR; @@ -1009,231 +978,73 @@ public: } return false; } + bool CorruptionPossible() { + return corruptionPossible; + } + unsigned char GetRejectCode() const { return chRejectCode; } + std::string GetRejectReason() const { return strRejectReason; } }; +/** An in-memory indexed chain of blocks. */ +class CChain { +private: + std::vector<CBlockIndex*> vChain; - - - - - -/** Describes a place in the block chain to another node such that if the - * other node doesn't have the same branch, it can find a recent common trunk. - * The further back it is, the further before the fork it may be. - */ -class CBlockLocator -{ -protected: - std::vector<uint256> vHave; public: - CBlockLocator() {} - - explicit CBlockLocator(const CBlockIndex* pindex) - { - Set(pindex); + /** Returns the index entry for the genesis block of this chain, or NULL if none. */ + CBlockIndex *Genesis() const { + return vChain.size() > 0 ? vChain[0] : NULL; } - explicit CBlockLocator(uint256 hashBlock); - - CBlockLocator(const std::vector<uint256>& vHaveIn) - { - vHave = vHaveIn; + /** Returns the index entry for the tip of this chain, or NULL if none. */ + CBlockIndex *Tip() const { + return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; } - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vHave); - ) - - void SetNull() - { - vHave.clear(); + /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ + CBlockIndex *operator[](int nHeight) const { + if (nHeight < 0 || nHeight >= (int)vChain.size()) + return NULL; + return vChain[nHeight]; } - bool IsNull() - { - return vHave.empty(); + /** Compare two chains efficiently. */ + friend bool operator==(const CChain &a, const CChain &b) { + return a.vChain.size() == b.vChain.size() && + a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1]; } - /** Given a block initialises the locator to that point in the chain. */ - void Set(const CBlockIndex* pindex); - /** Returns the distance in blocks this locator is from our chain head. */ - int GetDistanceBack(); - /** Returns the first best-chain block the locator contains. */ - CBlockIndex* GetBlockIndex(); - /** Returns the hash of the first best chain block the locator contains. */ - uint256 GetBlockHash(); - /** Returns the height of the first best chain block the locator has. */ - int GetHeight(); -}; - - - - - - - - -class CTxMemPool -{ -public: - static bool fChecks; - mutable CCriticalSection cs; - std::map<uint256, CTransaction> mapTx; - std::map<COutPoint, CInPoint> mapNextTx; - - bool accept(CValidationState &state, const CTransaction &tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee = false); - bool addUnchecked(const uint256& hash, const CTransaction &tx); - bool remove(const CTransaction &tx, bool fRecursive = false); - bool removeConflicts(const CTransaction &tx); - void clear(); - void queryHashes(std::vector<uint256>& vtxid); - void pruneSpent(const uint256& hash, CCoins &coins); - void check(CCoinsViewCache *pcoins) const; - - unsigned long size() - { - LOCK(cs); - return mapTx.size(); + /** Efficiently check whether a block is present in this chain. */ + bool Contains(const CBlockIndex *pindex) const { + return (*this)[pindex->nHeight] == pindex; } - bool exists(uint256 hash) - { - return (mapTx.count(hash) != 0); + /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */ + CBlockIndex *Next(const CBlockIndex *pindex) const { + if (Contains(pindex)) + return (*this)[pindex->nHeight + 1]; + else + return NULL; } - CTransaction& lookup(uint256 hash) - { - return mapTx[hash]; + /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ + int Height() const { + return vChain.size() - 1; } -}; - -extern CTxMemPool mempool; - -struct CCoinsStats -{ - int nHeight; - uint256 hashBlock; - uint64 nTransactions; - uint64 nTransactionOutputs; - uint64 nSerializedSize; - uint256 hashSerialized; - int64 nTotalAmount; - - CCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0), nTotalAmount(0) {} -}; - -/** Abstract view on the open txout dataset. */ -class CCoinsView -{ -public: - // Retrieve the CCoins (unspent transaction outputs) for a given txid - virtual bool GetCoins(const uint256 &txid, CCoins &coins); - - // Modify the CCoins for a given txid - virtual bool SetCoins(const uint256 &txid, const CCoins &coins); - - // Just check whether we have data for a given txid. - // This may (but cannot always) return true for fully spent transactions - virtual bool HaveCoins(const uint256 &txid); - - // Retrieve the block index whose state this CCoinsView currently represents - virtual CBlockIndex *GetBestBlock(); - // Modify the currently active block index - virtual bool SetBestBlock(CBlockIndex *pindex); + /** Set/initialize a chain with a given tip. Returns the forking point. */ + CBlockIndex *SetTip(CBlockIndex *pindex); - // Do a bulk modification (multiple SetCoins + one SetBestBlock) - virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); + /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */ + CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const; - // Calculate statistics about the unspent transaction output set - virtual bool GetStats(CCoinsStats &stats); - - // As we use CCoinsViews polymorphically, have a virtual destructor - virtual ~CCoinsView() {} -}; - -/** CCoinsView backed by another CCoinsView */ -class CCoinsViewBacked : public CCoinsView -{ -protected: - CCoinsView *base; - -public: - CCoinsViewBacked(CCoinsView &viewIn); - bool GetCoins(const uint256 &txid, CCoins &coins); - bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - CBlockIndex *GetBestBlock(); - bool SetBestBlock(CBlockIndex *pindex); - void SetBackend(CCoinsView &viewIn); - bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); - bool GetStats(CCoinsStats &stats); -}; - -/** CCoinsView that adds a memory cache for transactions to another CCoinsView */ -class CCoinsViewCache : public CCoinsViewBacked -{ -protected: - CBlockIndex *pindexTip; - std::map<uint256,CCoins> cacheCoins; - -public: - CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); - - // Standard CCoinsView methods - bool GetCoins(const uint256 &txid, CCoins &coins); - bool SetCoins(const uint256 &txid, const CCoins &coins); - bool HaveCoins(const uint256 &txid); - CBlockIndex *GetBestBlock(); - bool SetBestBlock(CBlockIndex *pindex); - bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); - - // Return a modifiable reference to a CCoins. Check HaveCoins first. - // Many methods explicitly require a CCoinsViewCache because of this method, to reduce - // copying. - CCoins &GetCoins(const uint256 &txid); - - // Push the modifications applied to this cache to its base. - // Failure to call this method before destruction will cause the changes to be forgotten. - bool Flush(); - - // Calculate the size of the cache (in number of transactions) - unsigned int GetCacheSize(); - - /** Amount of bitcoins coming in to a transaction - Note that lightweight clients may not know anything besides the hash of previous transactions, - so may not be able to calculate this. - - @param[in] tx transaction for which we are checking input total - @return Sum of value of all inputs (scriptSigs) - @see CTransaction::FetchInputs - */ - int64 GetValueIn(const CTransaction& tx); - - // Check whether all prevouts of the transaction are present in the UTXO set represented by this view - bool HaveInputs(const CTransaction& tx); - - const CTxOut &GetOutputFor(const CTxIn& input); - -private: - std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid); + /** Find the last common block between this chain and a locator. */ + CBlockIndex *FindFork(const CBlockLocator &locator) const; }; -/** CCoinsView that brings transactions from a memorypool into view. - It does not check for spendings by memory pool transactions. */ -class CCoinsViewMemPool : public CCoinsViewBacked -{ -protected: - CTxMemPool &mempool; +/** The currently-connected chain of blocks. */ +extern CChain chainActive; -public: - CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); - bool GetCoins(const uint256 &txid, CCoins &coins); - bool HaveCoins(const uint256 &txid); -}; /** Global variable that points to the active CCoinsView (protected by cs_main) */ extern CCoinsViewCache *pcoinsTip; @@ -1280,4 +1091,18 @@ public: ) }; + +class CWalletInterface { +protected: + virtual void SyncTransaction(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) =0; + virtual void EraseFromWallet(const uint256 &hash) =0; + virtual void SetBestChain(const CBlockLocator &locator) =0; + virtual void UpdatedTransaction(const uint256 &hash) =0; + virtual void Inventory(const uint256 &hash) =0; + virtual void ResendWalletTransactions() =0; + friend void ::RegisterWallet(CWalletInterface*); + friend void ::UnregisterWallet(CWalletInterface*); + friend void ::UnregisterAllWallets(); +}; + #endif |