X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.h;h=b8e6cb702e6430fc6107a4ed249202789081b43d;hb=9686d31d6c4e0ca008dcfe5becb1e0ce6ae37175;hp=60e483272ccbee9d1dc9373495ff88197d0a03e1;hpb=2387b89cbcea8b6e75ca24abb0595cc80d6ff3b5;p=novacoin.git diff --git a/src/main.h b/src/main.h index 60e4832..b8e6cb7 100644 --- a/src/main.h +++ b/src/main.h @@ -1,20 +1,25 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2011-2012 The PPCoin 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 +#include + +#include "timestamps.h" #include "bignum.h" +#include "sync.h" #include "net.h" #include "script.h" +#include "scrypt.h" +#include "ui_interface.h" -#ifdef WIN32 -#include /* for _commit */ -#endif - +#include #include +#include + +using namespace std; class CWallet; class CBlock; @@ -28,99 +33,112 @@ class CInv; class CRequestTracker; class CNode; +// +// Global state +// + static const unsigned int MAX_BLOCK_SIZE = 1000000; static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; -static const int64 MIN_TX_FEE = CENT; -static const int64 MIN_RELAY_TX_FEE = CENT; -static const int64 MAX_MONEY = 2000000000 * COIN; -static const int64 MAX_MINT_PROOF_OF_WORK = 9999 * COIN; -static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE; -inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } -static const int COINBASE_MATURITY_PPC = 500; -// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. -static const int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC -#ifdef USE_UPNP -static const int fHaveUPnP = true; -#else -static const int fHaveUPnP = false; -#endif - -static const uint256 hashGenesisBlockOfficial("0x0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3"); -static const uint256 hashGenesisBlockTestNet("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"); - -static const int64 nMaxClockDrift = 2 * 60 * 60; // two hours +static const unsigned int MAX_INV_SZ = 50000; -extern CScript COINBASE_FLAGS; +static const int64_t MIN_TX_FEE = CENT/10; +static const int64_t MIN_RELAY_TX_FEE = CENT/50; +static const int64_t MAX_MONEY = numeric_limits::max(); +static const int64_t MAX_MINT_PROOF_OF_WORK = 100 * COIN; +static const int64_t MAX_MINT_PROOF_OF_STAKE = 1 * COIN; +static const int64_t MIN_TXOUT_AMOUNT = CENT/100; +inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } +// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. +static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC +// Maximum number of script-checking threads allowed +static const int MAX_SCRIPTCHECK_THREADS = 16; +static const uint256 hashGenesisBlock("0x00000a060336cbb72fe969666d337b87198b1add2abaa59cca226820b32933a4"); +static const uint256 hashGenesisBlockTestNet("0x000c763e402f2436da9ed36c7286f62c3f6e5dbafce9ff289bd43d7459327eb"); +inline int64_t PastDrift(int64_t nTime) { return nTime - 2 * nOneHour; } // up to 2 hours from the past +inline int64_t FutureDrift(int64_t nTime) { return nTime + 2 * nOneHour; } // up to 2 hours from the future +extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; -extern std::map mapBlockIndex; -extern std::set > setStakeSeen; -extern uint256 hashGenesisBlock; +extern map mapBlockIndex; +extern set > setStakeSeen; +extern CBlockIndex* pindexGenesisBlock; +extern unsigned int nNodeLifespan; extern unsigned int nStakeMinAge; extern int nCoinbaseMaturity; -extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; -extern CBigNum bnBestChainTrust; -extern CBigNum bnBestInvalidTrust; +extern uint256 nBestChainTrust; +extern uint256 nBestInvalidTrust; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; extern unsigned int nTransactionsUpdated; -extern uint64 nLastBlockTx; -extern uint64 nLastBlockSize; -extern int64 nLastCoinStakeSearchInterval; -extern const std::string strMessageMagic; -extern double dHashesPerSec; -extern int64 nHPSTimerStart; -extern int64 nTimeBestReceived; +extern uint64_t nLastBlockTx; +extern uint64_t nLastBlockSize; +extern uint32_t nLastCoinStakeSearchInterval; +extern const string strMessageMagic; +extern int64_t nTimeBestReceived; extern CCriticalSection cs_setpwalletRegistered; -extern std::set setpwalletRegistered; -extern std::map mapOrphanBlocks; +extern set setpwalletRegistered; +extern uint32_t nNetworkID; +extern map mapOrphanBlocks; // Settings -extern int64 nTransactionFee; - - - +extern int64_t nTransactionFee; +extern int64_t nMinimumInputValue; +extern bool fUseFastIndex; +extern int nScriptCheckThreads; +extern const uint256 entropyStore[38]; +// Minimum disk space required - used in CheckDiskSpace() +static const uint64_t nMinDiskSpace = 52428800; class CReserveKey; class CTxDB; class CTxIndex; +class CScriptCheck; void RegisterWallet(CWallet* pwalletIn); void UnregisterWallet(CWallet* pwalletIn); +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true); bool ProcessBlock(CNode* pfrom, CBlock* pblock); -bool CheckDiskSpace(uint64 nAdditionalBytes=0); +bool CheckDiskSpace(uint64_t nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* AppendBlockFile(unsigned int& nFileRet); + +void UnloadBlockIndex(); bool LoadBlockIndex(bool fAllowNew=true); void PrintBlockTree(); +CBlockIndex* FindBlockByHeight(int nHeight); bool ProcessMessages(CNode* pfrom); -bool SendMessages(CNode* pto, bool fSendTrickle); -void GenerateBitcoins(bool fGenerate, CWallet* pwallet); -CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake=false); -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); -void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); -bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); +bool SendMessages(CNode* pto); +bool LoadExternalBlockFile(FILE* fileIn, CClientUIInterface& uiInterface); + +// Run an instance of the script checking thread +void ThreadScriptCheck(void* parg); +// Stop the script checking threads +void ThreadScriptCheckQuit(); + bool CheckProofOfWork(uint256 hash, unsigned int nBits); -int64 GetProofOfWorkReward(unsigned int nBits); -int64 GetProofOfStakeReward(int64 nCoinAge); -unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); +unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake); +int64_t GetProofOfWorkReward(unsigned int nBits, int64_t nFees=0); +int64_t GetProofOfStakeReward(int64_t nCoinAge, unsigned int nBits, int64_t nTime, bool bCoinYearOnly=false); +unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime); +unsigned int ComputeMinStake(unsigned int nBase, int64_t nTime, unsigned int nBlockTime); int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); -std::string GetWarnings(std::string strFor); +string GetWarnings(string strFor); +bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); uint256 WantedByOrphan(const CBlock* pblockOrphan); const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); -void BitcoinMiner(CWallet *pwallet, bool fProofOfStake); - +void ResendWalletTransactions(bool fForceResend=false); +bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType); @@ -128,17 +146,15 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake); - - -bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); +bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut); /** Position on disk for a particular transaction. */ class CDiskTxPos { public: - unsigned int nFile; - unsigned int nBlockPos; - unsigned int nTxPos; + uint32_t nFile; + uint32_t nBlockPos; + uint32_t nTxPos; CDiskTxPos() { @@ -153,8 +169,8 @@ public: } IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) - void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; } - bool IsNull() const { return (nFile == -1); } + void SetNull() { nFile = numeric_limits::max(); nBlockPos = 0; nTxPos = 0; } + bool IsNull() const { return (nFile == numeric_limits::max()); } friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b) { @@ -168,12 +184,13 @@ public: return !(a == b); } - std::string ToString() const + + string ToString() const { if (IsNull()) return "null"; else - return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos); + return strprintf("(nFile=%" PRIu32 ", nBlockPos=%" PRIu32 ", nTxPos=%" PRIu32 ")", nFile, nBlockPos, nTxPos); } void print() const @@ -189,12 +206,12 @@ class CInPoint { public: CTransaction* ptx; - unsigned int n; + uint32_t n; CInPoint() { SetNull(); } CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; } - void SetNull() { ptx = NULL; n = -1; } - bool IsNull() const { return (ptx == NULL && n == -1); } + void SetNull() { ptx = NULL; n = numeric_limits::max(); } + bool IsNull() const { return (ptx == NULL && n == numeric_limits::max()); } }; @@ -204,13 +221,13 @@ class COutPoint { public: uint256 hash; - unsigned int n; + uint32_t n; COutPoint() { SetNull(); } COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; } IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) - void SetNull() { hash = 0; n = -1; } - bool IsNull() const { return (hash == 0 && n == -1); } + void SetNull() { hash = 0; n = numeric_limits::max(); } + bool IsNull() const { return (hash == 0 && n == numeric_limits::max()); } friend bool operator<(const COutPoint& a, const COutPoint& b) { @@ -227,9 +244,9 @@ public: return !(a == b); } - std::string ToString() const + string ToString() const { - return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n); + return strprintf("COutPoint(%s, %" PRIu32 ")", hash.ToString().substr(0,10).c_str(), n); } void print() const @@ -250,21 +267,21 @@ class CTxIn public: COutPoint prevout; CScript scriptSig; - unsigned int nSequence; + uint32_t nSequence; CTxIn() { - nSequence = std::numeric_limits::max(); + nSequence = numeric_limits::max(); } - explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits::max()) + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=numeric_limits::max()) { prevout = prevoutIn; scriptSig = scriptSigIn; nSequence = nSequenceIn; } - CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits::max()) + CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=numeric_limits::max()) { prevout = COutPoint(hashPrevTx, nOut); scriptSig = scriptSigIn; @@ -280,7 +297,7 @@ public: bool IsFinal() const { - return (nSequence == std::numeric_limits::max()); + return (nSequence == numeric_limits::max()); } friend bool operator==(const CTxIn& a, const CTxIn& b) @@ -295,22 +312,22 @@ public: return !(a == b); } - std::string ToStringShort() const + string ToStringShort() const { return strprintf(" %s %d", prevout.hash.ToString().c_str(), prevout.n); } - std::string ToString() const + string ToString() const { - std::string str; + string str; str += "CTxIn("; str += prevout.ToString(); if (prevout.IsNull()) str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); else str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); - if (nSequence != std::numeric_limits::max()) - str += strprintf(", nSequence=%u", nSequence); + if (nSequence != numeric_limits::max()) + str += strprintf(", nSequence=%" PRIu32, nSequence); str += ")"; return str; } @@ -330,7 +347,7 @@ public: class CTxOut { public: - int64 nValue; + int64_t nValue; CScript scriptPubKey; CTxOut() @@ -338,7 +355,7 @@ public: SetNull(); } - CTxOut(int64 nValueIn, CScript scriptPubKeyIn) + CTxOut(int64_t nValueIn, CScript scriptPubKeyIn) { nValue = nValueIn; scriptPubKey = scriptPubKeyIn; @@ -388,12 +405,12 @@ public: return !(a == b); } - std::string ToStringShort() const + string ToStringShort() const { return strprintf(" out %s %s", FormatMoney(nValue).c_str(), scriptPubKey.ToString(true).c_str()); } - std::string ToString() const + string ToString() const { if (IsEmpty()) return "CTxOut(empty)"; if (scriptPubKey.size() < 6) @@ -414,10 +431,10 @@ enum GetMinFee_mode { GMF_BLOCK, GMF_RELAY, - GMF_SEND, + GMF_SEND }; -typedef std::map > MapPrevTx; +typedef map > MapPrevTx; /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. @@ -425,11 +442,12 @@ typedef std::map > MapPrevTx; class CTransaction { public: + static const int CURRENT_VERSION=1; int nVersion; - unsigned int nTime; - std::vector vin; - std::vector vout; - unsigned int nLockTime; + uint32_t nTime; + vector vin; + vector vout; + uint32_t nLockTime; // Denial-of-service detection: mutable int nDoS; @@ -452,8 +470,8 @@ public: void SetNull() { - nVersion = 1; - nTime = GetAdjustedTime(); + nVersion = CTransaction::CURRENT_VERSION; + nTime = (uint32_t) GetAdjustedTime(); vin.clear(); vout.clear(); nLockTime = 0; @@ -470,7 +488,7 @@ public: return SerializeHash(*this); } - bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const + bool IsFinal(int nBlockHeight=0, int64_t nBlockTime=0) const { // Time based nLockTime implemented in 0.1.6 if (nLockTime == 0) @@ -479,9 +497,9 @@ public: nBlockHeight = nBestHeight; if (nBlockTime == 0) nBlockTime = GetAdjustedTime(); - if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime)) + if ((int64_t)nLockTime < ((int64_t)nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) return true; - BOOST_FOREACH(const CTxIn& txin, vin) + for(const CTxIn& txin : vin) if (!txin.IsFinal()) return false; return true; @@ -496,7 +514,7 @@ public: return false; bool fNewer = false; - unsigned int nLowest = std::numeric_limits::max(); + unsigned int nLowest = numeric_limits::max(); for (unsigned int i = 0; i < vin.size(); i++) { if (vin[i].nSequence != old.vin[i].nSequence) @@ -530,7 +548,12 @@ public: /** Check for standard transaction types @return True if all outputs (scriptPubKeys) use only standard transaction forms */ - bool IsStandard() const; + bool IsStandard(string& strReason) const; + bool IsStandard() const + { + string strReason; + return IsStandard(strReason); + } /** Check for standard transaction types @param[in] mapInputs Map of previous transactions that have outputs we're spending @@ -556,14 +579,14 @@ public: /** Amount of bitcoins spent by this transaction. @return sum of all outputs (note: does not include fees) */ - int64 GetValueOut() const + int64_t GetValueOut() const { - int64 nValueOut = 0; - BOOST_FOREACH(const CTxOut& txout, vout) + int64_t nValueOut = 0; + for(const CTxOut& txout : vout) { nValueOut += txout.nValue; if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut)) - throw std::runtime_error("CTransaction::GetValueOut() : value out of range"); + throw runtime_error("CTransaction::GetValueOut() : value out of range"); } return nValueOut; } @@ -576,7 +599,7 @@ public: @return Sum of value of all inputs (scriptSigs) @see CTransaction::FetchInputs */ - int64 GetValueIn(const MapPrevTx& mapInputs) const; + int64_t GetValueIn(const MapPrevTx& mapInputs) const; static bool AllowFree(double dPriority) { @@ -585,57 +608,11 @@ public: return dPriority > COIN * 144 / 250; } - int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK) const - { - // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE - int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE; - - unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); - unsigned int nNewBlockSize = nBlockSize + nBytes; - int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; - - if (fAllowFree) - { - if (nBlockSize == 1) - { - // Transactions under 10K are free - // (about 4500bc if made of 50bc inputs) - if (nBytes < 10000) - nMinFee = 0; - } - else - { - // Free transaction area - if (nNewBlockSize < 27000) - nMinFee = 0; - } - } - - // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01 - if (nMinFee < nBaseFee) - { - BOOST_FOREACH(const CTxOut& txout, vout) - if (txout.nValue < CENT) - nMinFee = nBaseFee; - } - - // Raise the price as the block approaches full - if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) - { - if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN) - return MAX_MONEY; - nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize); - } - - if (!MoneyRange(nMinFee)) - nMinFee = MAX_MONEY; - return nMinFee; - } - + int64_t GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK, unsigned int nBytes = 0) const; bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL) { - CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); + auto filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); @@ -646,8 +623,8 @@ public: try { filein >> *this; } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + catch (const exception&) { + return error("%s() : deserialize or I/O error", BOOST_CURRENT_FUNCTION); } // Return file pointer @@ -674,19 +651,18 @@ public: return !(a == b); } - - std::string ToStringShort() const + string ToStringShort() const { - std::string str; + string str; str += strprintf("%s %s", GetHash().ToString().c_str(), IsCoinBase()? "base" : (IsCoinStake()? "stake" : "user")); return str; } - std::string ToString() const + string ToString() const { - std::string str; + string str; str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction"); - str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n", + str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%" PRIszu ", vout.size=%" PRIszu ", nLockTime=%d)\n", GetHash().ToString().substr(0,10).c_str(), nTime, nVersion, @@ -721,7 +697,7 @@ public: @param[out] fInvalid returns true if transaction is invalid @return Returns true if all inputs are in txdb or mapTestPool */ - bool FetchInputs(CTxDB& txdb, const std::map& mapTestPool, + bool FetchInputs(CTxDB& txdb, const map& mapTestPool, bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid); /** Sanity check previous transactions, then, if all checks succeed, @@ -733,22 +709,50 @@ public: @param[in] pindexBlock @param[in] fBlock true if called from ConnectBlock @param[in] fMiner true if called from CreateNewBlock - @param[in] fStrictPayToScriptHash true if fully validating p2sh transactions + @param[in] fScriptChecks enable scripts validation? + @param[in] flags STRICT_FLAGS script validation flags + @param[in] pvChecks NULL If pvChecks is not NULL, script checks are pushed onto it instead of being performed inline. @return Returns true if all checks succeed */ - bool ConnectInputs(CTxDB& txdb, MapPrevTx inputs, - std::map& mapTestPool, const CDiskTxPos& posThisTx, - const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash=true); + bool ConnectInputs(CTxDB& txdb, MapPrevTx inputs, map& mapTestPool, const CDiskTxPos& posThisTx, const CBlockIndex* pindexBlock, + bool fBlock, bool fMiner, bool fScriptChecks=true, + unsigned int flags=STRICT_FLAGS, vector *pvChecks = NULL); bool ClientConnectInputs(); bool CheckTransaction() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); - bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const; // ppcoin: get transaction coin age - bool CheckProofOfStake(unsigned int nBits) const; + bool GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const; // ppcoin: get transaction coin age protected: const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const; }; +/** Closure representing one script verification + * Note that this stores references to the spending transaction */ +class CScriptCheck +{ +private: + CScript scriptPubKey; + const CTransaction *ptxTo = nullptr; + unsigned int nIn = 0; + unsigned int nFlags = 0; + int nHashType = 0; + +public: + CScriptCheck() {} + CScriptCheck(const CTransaction& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, int nHashTypeIn) : + scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), nHashType(nHashTypeIn) { } + + bool operator()() const; + + void swap(CScriptCheck &check) { + scriptPubKey.swap(check.scriptPubKey); + std::swap(ptxTo, check.ptxTo); + std::swap(nIn, check.nIn); + std::swap(nFlags, check.nFlags); + std::swap(nHashType, check.nHashType); + } +}; @@ -758,8 +762,8 @@ class CMerkleTx : public CTransaction { public: uint256 hashBlock; - std::vector vMerkleBranch; - int nIndex; + vector vMerkleBranch; + int32_t nIndex; // memory only mutable bool fMerkleVerified; @@ -813,7 +817,7 @@ class CTxIndex { public: CDiskTxPos pos; - std::vector vSpent; + vector vSpent; CTxIndex() { @@ -856,11 +860,8 @@ public: return !(a == b); } int GetDepthInMainChain() const; - -}; - - +}; /** Nodes collect new transactions into a block, hash them into a hash tree, @@ -877,21 +878,22 @@ class CBlock { public: // header - int nVersion; + static const int CURRENT_VERSION=6; + int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; - unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; + uint32_t nTime; + uint32_t nBits; + uint32_t nNonce; // network and disk - std::vector vtx; + vector vtx; - // ppcoin: block signature - signed by coin base txout[0]'s owner - std::vector vchBlockSig; + // ppcoin: block signature - signed by one of the coin base txout[N]'s owner + vector vchBlockSig; // memory only - mutable std::vector vMerkleTree; + mutable vector vMerkleTree; // Denial-of-service detection: mutable int nDoS; @@ -927,7 +929,7 @@ public: void SetNull() { - nVersion = 1; + nVersion = CBlock::CURRENT_VERSION; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; @@ -946,16 +948,39 @@ public: uint256 GetHash() const { - return Hash(BEGIN(nVersion), END(nNonce)); + return scrypt_blockhash((const uint8_t*)&nVersion); } - int64 GetBlockTime() const + int64_t GetBlockTime() const { - return (int64)nTime; + return (int64_t)nTime; } void UpdateTime(const CBlockIndex* pindexPrev); + // ppcoin: entropy bit for stake modifier if chosen by modifier + unsigned int GetStakeEntropyBit(unsigned int nHeight) const + { + // Protocol switch to support p2pool at novacoin block #9689 + if (nHeight >= 9689 || fTestNet) + { + // Take last bit of block hash as entropy bit + auto nEntropyBit = (GetHash().Get32()) & (uint32_t)1; + if (fDebug && GetBoolArg("-printstakemodifier")) + printf("GetStakeEntropyBit: nTime=%" PRIu32 " hashBlock=%s nEntropyBit=%" PRIu32 "\n", nTime, GetHash().ToString().c_str(), nEntropyBit); + return nEntropyBit; + } + + // Before novacoin block #9689 - get from pregenerated table + int nBitNum = nHeight & 0xFF; + int nItemNum = nHeight / 0xFF; + + auto nEntropyBit = ((entropyStore[nItemNum] & (uint256(1) << nBitNum)) >> nBitNum).Get32(); + if (fDebug && GetBoolArg("-printstakemodifier")) + printf("GetStakeEntropyBit: from pregenerated table, nHeight=%" PRIu32 " nEntropyBit=%" PRIu32 "\n", nHeight, nEntropyBit); + return nEntropyBit; + } + // ppcoin: two types of block: proof-of-work or proof-of-stake bool IsProofOfStake() const { @@ -967,48 +992,50 @@ public: return !IsProofOfStake(); } - std::pair GetProofOfStake() const + pair GetProofOfStake() const { - return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0); + if (IsProofOfStake()) + return { vtx[1].vin[0].prevout, vtx[1].nTime }; + return { COutPoint(), (unsigned int)0 }; } // ppcoin: get max transaction timestamp - int64 GetMaxTransactionTime() const + int64_t GetMaxTransactionTime() const { - int64 maxTransactionTime = 0; - BOOST_FOREACH(const CTransaction& tx, vtx) - maxTransactionTime = std::max(maxTransactionTime, (int64)tx.nTime); + int64_t maxTransactionTime = 0; + for(const auto& tx : vtx) + maxTransactionTime = max(maxTransactionTime, (int64_t)tx.nTime); return maxTransactionTime; } uint256 BuildMerkleTree() const { vMerkleTree.clear(); - BOOST_FOREACH(const CTransaction& tx, vtx) + for(const auto& tx : vtx) vMerkleTree.push_back(tx.GetHash()); int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + for (int nSize = (int)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]))); + int i2 = min(i+1, nSize-1); + vMerkleTree.push_back(Hash(vMerkleTree[j+i].begin(), vMerkleTree[j+i].end(), + vMerkleTree[j+i2].begin(), vMerkleTree[j+i2].end())); } j += nSize; } return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); } - std::vector GetMerkleBranch(int nIndex) const + vector GetMerkleBranch(int nIndex) const { if (vMerkleTree.empty()) BuildMerkleTree(); - std::vector vMerkleBranch; + vector vMerkleBranch; int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + for (int nSize = (int)vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { - int i = std::min(nIndex^1, nSize-1); + int i = min(nIndex^1, nSize-1); vMerkleBranch.push_back(vMerkleTree[j+i]); nIndex >>= 1; j += nSize; @@ -1016,16 +1043,16 @@ public: return vMerkleBranch; } - static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) + static uint256 CheckMerkleBranch(uint256 hash, const vector& vMerkleBranch, int nIndex) { if (nIndex == -1) return 0; - BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + for(const uint256& otherside : vMerkleBranch) { if (nIndex & 1) - hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + hash = Hash(otherside.begin(), otherside.end(), hash.begin(), hash.end()); else - hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + hash = Hash(hash.begin(), hash.end(), otherside.begin(), otherside.end()); nIndex >>= 1; } return hash; @@ -1035,15 +1062,13 @@ public: bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet) { // Open history file to append - CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); + auto fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); if (!fileout) return error("CBlock::WriteToDisk() : AppendBlockFile failed"); // Write index header - unsigned char pchMessageStart[4]; - GetMessageStart(pchMessageStart, true); unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(pchMessageStart) << nSize; + fileout << nNetworkID << nSize; // Write block long fileOutPos = ftell(fileout); @@ -1055,13 +1080,7 @@ public: // Flush stdio buffers and commit to disk before returning fflush(fileout); if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) - { -#ifdef WIN32 - _commit(_fileno(fileout)); -#else - fsync(fileno(fileout)); -#endif - } + FileCommit(fileout); return true; } @@ -1071,7 +1090,7 @@ public: SetNull(); // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); + auto filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); if (!fReadTransactions) @@ -1081,8 +1100,8 @@ public: try { filein >> *this; } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + catch (const exception&) { + return error("%s() : deserialize or I/O error", BOOST_CURRENT_FUNCTION); } // Check the header @@ -1096,11 +1115,11 @@ public: void print() const { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d, vchBlockSig=%s)\n", - GetHash().ToString().substr(0,20).c_str(), + printf("CBlock(hash=%s, ver=%" PRId32 ", hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%" PRIu32 ", nBits=%08x, nNonce=%" PRIu32 ", vtx=%" PRIszu ", vchBlockSig=%s)\n", + GetHash().ToString().c_str(), nVersion, - hashPrevBlock.ToString().substr(0,20).c_str(), - hashMerkleRoot.ToString().substr(0,10).c_str(), + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), nTime, nBits, nNonce, vtx.size(), HexStr(vchBlockSig.begin(), vchBlockSig.end()).c_str()); @@ -1117,14 +1136,13 @@ public: bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); - bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); + bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck=false); bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew); bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); - bool CheckBlock() const; + bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true, bool fCheckSig=true) const; bool AcceptBlock(); - bool GetCoinAge(uint64& nCoinAge) const; // ppcoin: calculate total coin age spent in block - bool SignBlock(const CKeyStore& keystore); + bool GetCoinAge(uint64_t& nCoinAge) const; // ppcoin: calculate total coin age spent in block bool CheckBlockSignature() const; private: @@ -1149,23 +1167,36 @@ public: const uint256* phashBlock; CBlockIndex* pprev; CBlockIndex* pnext; - unsigned int nFile; - unsigned int nBlockPos; - CBigNum bnChainTrust; // ppcoin: trust score of block chain - int nHeight; - int64 nMint; - int64 nMoneySupply; - bool fProofOfStake; // ppcoin: is the block of proof-of-stake type + uint32_t nFile; + uint32_t nBlockPos; + uint256 nChainTrust; // ppcoin: trust score of block chain + int32_t nHeight; + + int64_t nMint; + int64_t nMoneySupply; + + uint32_t nFlags; // ppcoin: block index flags + enum + { + BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block + BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier + BLOCK_STAKE_MODIFIER = (1 << 2) // regenerated stake modifier + }; + + uint64_t nStakeModifier; // hash modifier for proof-of-stake + uint32_t nStakeModifierChecksum; // checksum of index; in-memeory only + + // proof-of-stake specific fields COutPoint prevoutStake; - unsigned int nStakeTime; + uint32_t nStakeTime; + uint256 hashProofOfStake; // block header - int nVersion; - uint256 hashMerkleRoot; - unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; - + int32_t nVersion; + uint256 hashMerkleRoot; + uint32_t nTime; + uint32_t nBits; + uint32_t nNonce; CBlockIndex() { @@ -1175,10 +1206,13 @@ public: nFile = 0; nBlockPos = 0; nHeight = 0; - bnChainTrust = 0; + nChainTrust = 0; nMint = 0; nMoneySupply = 0; - fProofOfStake = true; + nFlags = 0; + nStakeModifier = 0; + nStakeModifierChecksum = 0; + hashProofOfStake = 0; prevoutStake.SetNull(); nStakeTime = 0; @@ -1197,12 +1231,16 @@ public: nFile = nFileIn; nBlockPos = nBlockPosIn; nHeight = 0; - bnChainTrust = 0; + nChainTrust = 0; nMint = 0; nMoneySupply = 0; - fProofOfStake = block.IsProofOfStake(); - if (fProofOfStake) + nFlags = 0; + nStakeModifier = 0; + nStakeModifierChecksum = 0; + hashProofOfStake = 0; + if (block.IsProofOfStake()) { + SetProofOfStake(); prevoutStake = block.vtx[1].vin[0].prevout; nStakeTime = block.vtx[1].nTime; } @@ -1237,19 +1275,12 @@ public: return *phashBlock; } - int64 GetBlockTime() const + int64_t GetBlockTime() const { - return (int64)nTime; + return (int64_t)nTime; } - CBigNum GetBlockTrust() const - { - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - if (bnTarget <= 0) - return 0; - return (fProofOfStake? (CBigNum(1)<<256) / (bnTarget+1) : 1); - } + uint256 GetBlockTrust() const; bool IsInMainChain() const { @@ -1258,41 +1289,26 @@ public: bool CheckIndex() const { - return IsProofOfWork() ? CheckProofOfWork(GetBlockHash(), nBits) : true; - } - - bool EraseBlockFromDisk() - { - // Open history file - CAutoFile fileout = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb+"), SER_DISK, CLIENT_VERSION); - if (!fileout) - return false; - - // Overwrite with empty null block - CBlock block; - block.SetNull(); - fileout << block; - return true; } 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) *(--pbegin) = pindex->GetBlockTime(); - std::sort(pbegin, pend); + sort(pbegin, pend); return pbegin[(pend - pbegin)/2]; } - int64 GetMedianTime() const + int64_t GetMedianTime() const { const CBlockIndex* pindex = this; for (int i = 0; i < nMedianTimeSpan/2; i++) @@ -1304,24 +1320,65 @@ public: return pindex->GetMedianTimePast(); } + /** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last nToCheck blocks, starting at pstart and going backwards. + */ + static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, + unsigned int nRequired, unsigned int nToCheck); + + bool IsProofOfWork() const { - return !fProofOfStake; + return !(nFlags & BLOCK_PROOF_OF_STAKE); } bool IsProofOfStake() const { - return fProofOfStake; + return (nFlags & BLOCK_PROOF_OF_STAKE); + } + + void SetProofOfStake() + { + nFlags |= BLOCK_PROOF_OF_STAKE; } - std::string ToString() const + unsigned int GetStakeEntropyBit() const { - return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, fProofOfStake=%d prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)", - pprev, pnext, nFile, nBlockPos, nHeight, + return ((nFlags & BLOCK_STAKE_ENTROPY) >> 1); + } + + bool SetStakeEntropyBit(unsigned int nEntropyBit) + { + if (nEntropyBit > 1) + return false; + nFlags |= (nEntropyBit? BLOCK_STAKE_ENTROPY : 0); + return true; + } + + bool GeneratedStakeModifier() const + { + return (nFlags & BLOCK_STAKE_MODIFIER) != 0; + } + + void SetStakeModifier(uint64_t nModifier, bool fGeneratedStakeModifier) + { + nStakeModifier = nModifier; + if (fGeneratedStakeModifier) + nFlags |= BLOCK_STAKE_MODIFIER; + } + + string ToString() const + { + return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016" PRIx64 ", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)", + (const void*)pprev, (const void*)pnext, nFile, nBlockPos, nHeight, FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).c_str(), - fProofOfStake, prevoutStake.ToString().c_str(), nStakeTime, - hashMerkleRoot.ToString().substr(0,10).c_str(), - GetBlockHash().ToString().substr(0,20).c_str()); + GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW", + nStakeModifier, nStakeModifierChecksum, + hashProofOfStake.ToString().c_str(), + prevoutStake.ToString().c_str(), nStakeTime, + hashMerkleRoot.ToString().c_str(), + GetBlockHash().ToString().c_str()); } void print() const @@ -1335,6 +1392,9 @@ public: /** Used to marshal pointers into hashes for db storage. */ class CDiskBlockIndex : public CBlockIndex { +private: + uint256 blockHash; + public: uint256 hashPrev; uint256 hashNext; @@ -1343,6 +1403,7 @@ public: { hashPrev = 0; hashNext = 0; + blockHash = 0; } explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) @@ -1362,16 +1423,19 @@ public: READWRITE(nHeight); READWRITE(nMint); READWRITE(nMoneySupply); - READWRITE(fProofOfStake); - if (fProofOfStake) + READWRITE(nFlags); + READWRITE(nStakeModifier); + if (IsProofOfStake()) { READWRITE(prevoutStake); READWRITE(nStakeTime); + READWRITE(hashProofOfStake); } else if (fRead) { const_cast(this)->prevoutStake.SetNull(); const_cast(this)->nStakeTime = 0; + const_cast(this)->hashProofOfStake = 0; } // block header @@ -1381,10 +1445,14 @@ public: READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); + READWRITE(blockHash); ) uint256 GetBlockHash() const { + if (fUseFastIndex && blockHash != 0) + return blockHash; + CBlock block; block.nVersion = nVersion; block.hashPrevBlock = hashPrev; @@ -1392,18 +1460,20 @@ public: block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; - return block.GetHash(); - } + const_cast(this)->blockHash = block.GetHash(); - std::string ToString() const + return blockHash; + } + + string ToString() const { - std::string str = "CDiskBlockIndex("; + string str = "CDiskBlockIndex("; str += CBlockIndex::ToString(); str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", GetBlockHash().ToString().c_str(), - hashPrev.ToString().substr(0,20).c_str(), - hashNext.ToString().substr(0,20).c_str()); + hashPrev.ToString().c_str(), + hashNext.ToString().c_str()); return str; } @@ -1427,7 +1497,7 @@ public: class CBlockLocator { protected: - std::vector vHave; + vector vHave; public: CBlockLocator() @@ -1441,12 +1511,12 @@ public: explicit CBlockLocator(uint256 hashBlock) { - std::map::iterator mi = mapBlockIndex.find(hashBlock); + auto mi = mapBlockIndex.find(hashBlock); if (mi != mapBlockIndex.end()) Set((*mi).second); } - CBlockLocator(const std::vector& vHaveIn) + CBlockLocator(const vector& vHaveIn) { vHave = vHaveIn; } @@ -1482,7 +1552,7 @@ public: if (vHave.size() > 10) nStep *= 2; } - vHave.push_back(hashGenesisBlock); + vHave.push_back((!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)); } int GetDistanceBack() @@ -1490,12 +1560,12 @@ public: // Retrace how far back it was in the sender's branch int nDistance = 0; int nStep = 1; - BOOST_FOREACH(const uint256& hash, vHave) + for(const auto& hash : vHave) { - std::map::iterator mi = mapBlockIndex.find(hash); + auto mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { - CBlockIndex* pindex = (*mi).second; + auto pindex = (*mi).second; if (pindex->IsInMainChain()) return nDistance; } @@ -1509,12 +1579,12 @@ public: CBlockIndex* GetBlockIndex() { // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, vHave) + for(const auto& hash : vHave) { - std::map::iterator mi = mapBlockIndex.find(hash); + auto mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { - CBlockIndex* pindex = (*mi).second; + auto pindex = (*mi).second; if (pindex->IsInMainChain()) return pindex; } @@ -1525,17 +1595,17 @@ public: uint256 GetBlockHash() { // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, vHave) + for(const uint256& hash : vHave) { - std::map::iterator mi = mapBlockIndex.find(hash); + auto mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { - CBlockIndex* pindex = (*mi).second; + auto pindex = (*mi).second; if (pindex->IsInMainChain()) return hash; } } - return hashGenesisBlock; + return (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet); } int GetHeight() @@ -1554,231 +1624,32 @@ public: - -/** Alerts are for notifying old versions if they become too obsolete and - * need to upgrade. The message is displayed in the status bar. - * Alert messages are broadcast as a vector of signed data. Unserializing may - * not read the entire buffer if the alert is for a newer version, but older - * versions can still relay the original data. - */ -class CUnsignedAlert -{ -public: - int nVersion; - int64 nRelayUntil; // when newer nodes stop relaying to newer nodes - int64 nExpiration; - int nID; - int nCancel; - std::set setCancel; - int nMinVer; // lowest version inclusive - int nMaxVer; // highest version inclusive - std::set setSubVer; // empty matches all - int nPriority; - - // Actions - std::string strComment; - std::string strStatusBar; - std::string strReserved; - - IMPLEMENT_SERIALIZE - ( - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(nRelayUntil); - READWRITE(nExpiration); - READWRITE(nID); - READWRITE(nCancel); - READWRITE(setCancel); - READWRITE(nMinVer); - READWRITE(nMaxVer); - READWRITE(setSubVer); - READWRITE(nPriority); - - READWRITE(strComment); - READWRITE(strStatusBar); - READWRITE(strReserved); - ) - - void SetNull() - { - nVersion = 1; - nRelayUntil = 0; - nExpiration = 0; - nID = 0; - nCancel = 0; - setCancel.clear(); - nMinVer = 0; - nMaxVer = 0; - setSubVer.clear(); - nPriority = 0; - - strComment.clear(); - strStatusBar.clear(); - strReserved.clear(); - } - - std::string ToString() const - { - std::string strSetCancel; - BOOST_FOREACH(int n, setCancel) - strSetCancel += strprintf("%d ", n); - std::string strSetSubVer; - BOOST_FOREACH(std::string str, setSubVer) - strSetSubVer += "\"" + str + "\" "; - return strprintf( - "CAlert(\n" - " nVersion = %d\n" - " nRelayUntil = %"PRI64d"\n" - " nExpiration = %"PRI64d"\n" - " nID = %d\n" - " nCancel = %d\n" - " setCancel = %s\n" - " nMinVer = %d\n" - " nMaxVer = %d\n" - " setSubVer = %s\n" - " nPriority = %d\n" - " strComment = \"%s\"\n" - " strStatusBar = \"%s\"\n" - ")\n", - nVersion, - nRelayUntil, - nExpiration, - nID, - nCancel, - strSetCancel.c_str(), - nMinVer, - nMaxVer, - strSetSubVer.c_str(), - nPriority, - strComment.c_str(), - strStatusBar.c_str()); - } - - void print() const - { - printf("%s", ToString().c_str()); - } -}; - -/** An alert is a combination of a serialized CUnsignedAlert and a signature. */ -class CAlert : public CUnsignedAlert -{ -public: - std::vector vchMsg; - std::vector vchSig; - - CAlert() - { - SetNull(); - } - - IMPLEMENT_SERIALIZE - ( - READWRITE(vchMsg); - READWRITE(vchSig); - ) - - void SetNull() - { - CUnsignedAlert::SetNull(); - vchMsg.clear(); - vchSig.clear(); - } - - bool IsNull() const - { - return (nExpiration == 0); - } - - uint256 GetHash() const - { - return SerializeHash(*this); - } - - bool IsInEffect() const - { - return (GetAdjustedTime() < nExpiration); - } - - bool Cancels(const CAlert& alert) const - { - if (!IsInEffect()) - return false; // this was a no-op before 31403 - return (alert.nID <= nCancel || setCancel.count(alert.nID)); - } - - bool AppliesTo(int nVersion, std::string strSubVerIn) const - { - // TODO: rework for client-version-embedded-in-strSubVer ? - return (IsInEffect() && - nMinVer <= nVersion && nVersion <= nMaxVer && - (setSubVer.empty() || setSubVer.count(strSubVerIn))); - } - - bool AppliesToMe() const - { - return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); - } - - bool RelayTo(CNode* pnode) const - { - if (!IsInEffect()) - return false; - // returns true if wasn't already contained in the set - if (pnode->setKnown.insert(GetHash()).second) - { - if (AppliesTo(pnode->nVersion, pnode->strSubVer) || - AppliesToMe() || - GetAdjustedTime() < nRelayUntil) - { - pnode->PushMessage("alert", *this); - return true; - } - } - return false; - } - - bool CheckSignature() - { - CKey key; - if (!key.SetPubKey(ParseHex("04a0a849dd49b113d3179a332dd77715c43be4d0076e2f19e66de23dd707e56630f792f298dfd209bf042bb3561f4af6983f3d81e439737ab0bf7f898fecd21aab"))) - return error("CAlert::CheckSignature() : SetPubKey failed"); - if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - return error("CAlert::CheckSignature() : verify signature failed"); - - // Now unserialize the data - CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); - sMsg >> *(CUnsignedAlert*)this; - return true; - } - - bool ProcessAlert(); -}; - class CTxMemPool { public: mutable CCriticalSection cs; - std::map mapTx; - std::map mapNextTx; + map mapTx; + map mapNextTx; bool accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs); - bool addUnchecked(CTransaction &tx); + bool addUnchecked(const uint256& hash, CTransaction &tx); bool remove(CTransaction &tx); + void clear(); + void queryHashes(vector& vtxid); - unsigned long size() + size_t size() { LOCK(cs); return mapTx.size(); } - bool exists(uint256 hash) + bool exists(const uint256 &hash) { return (mapTx.count(hash) != 0); } - CTransaction& lookup(uint256 hash) + CTransaction& lookup(const uint256 &hash) { return mapTx[hash]; }