// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 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 TRIANGLES_MAIN_H #define TRIANGLES_MAIN_H #include "bignum.h" #include "sync.h" #include "net.h" #include "script.h" #include "scrypt.h" #include "hashblock.h" #include "checkqueue.h" #include "sigcache.h" #include class CWallet; class CBlock; class CBlockIndex; class CKeyItem; class CReserveKey; class COutPoint; class CAddress; class CInv; class CRequestTracker; class CNode; class CScriptCheck; static const int CUTOFF_POW_BLOCK = 9000; static const int CRAPCHAIN_CUTOFF_BLOCK = 17691; // pre-Pharao (version 4) blockchain until block 17691 static const int FORK_HEIGHT_V5 = 17651; // v5 hard fork: decentralization + Tor v3 (next block after last checkpoint) static const int FORK_HEIGHT_V5_4 = 2186941; // v5.4: tighter timestamps, deterministic fork resolution 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 unsigned int MAX_ORPHAN_BLOCKS = 750; static const unsigned int MAX_ORPHAN_BLOCKS_IBD = 1500; static const unsigned int MAX_REORG_DEPTH = 100; // reject reorgs deeper than this (finality) static const unsigned int MAX_INV_SZ = 50000; static const int64_t MIN_TX_FEE = (1 * CENT) / 100; static const int64_t MIN_RELAY_TX_FEE = (1 * CENT) / 100; static const int64_t MAX_MONEY = 2222222 * COIN; static const int64_t COIN_YEAR_REWARD = 33 * CENT; // 33% per year static const int64_t MAX_TRI_PROOF_OF_STAKE = 0.33 * COIN; static const int MODIFIER_INTERVAL_SWITCH = 1; 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 #ifdef USE_UPNP static const int fHaveUPnP = true; #else static const int fHaveUPnP = false; #endif static const uint256 hashGenesisBlockOfficial("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); static const uint256 hashGenesisBlockTestNet ("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); inline int64_t GetMaxTimeDrift(int nHeight) { return (nHeight >= FORK_HEIGHT_V5_4) ? 90 : 10 * 60; } inline int64_t PastDrift(int64_t nTime, int nHeight) { return nTime - GetMaxTimeDrift(nHeight); } inline int64_t FutureDrift(int64_t nTime, int nHeight) { return nTime + GetMaxTimeDrift(nHeight); } // Height-less overloads always use post-V5.4 rules (90-second drift). // All nodes are well past FORK_HEIGHT_V5_4; using the global nBestHeight // here previously caused nodes at different heights to disagree on block // validity during the fork transition — a consensus-splitting bug. inline int64_t PastDrift(int64_t nTime) { return PastDrift(nTime, FORK_HEIGHT_V5_4); } inline int64_t FutureDrift(int64_t nTime) { return FutureDrift(nTime, FORK_HEIGHT_V5_4); } extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern std::map mapBlockIndex; extern std::set > setStakeSeen; extern CBlockIndex* pindexGenesisBlock; extern unsigned int nStakeMinAge; extern unsigned int nNodeLifespan; extern int nCoinbaseMaturity; extern int nBestHeight; extern uint256 nBestChainTrust; extern uint256 nBestInvalidTrust; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; extern CBlockIndex* pindexFinalized; // auto-checkpoint: deepest finalized block extern unsigned int nTransactionsUpdated; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; extern int64_t nLastCoinStakeSearchInterval; extern const std::string strMessageMagic; extern int64_t nTimeBestReceived; extern CCriticalSection cs_setpwalletRegistered; extern std::set setpwalletRegistered; extern unsigned char pchMessageStart[4]; extern std::map mapOrphanBlocks; // Settings extern int64_t nTransactionFee; extern int64_t nReserveBalance; extern int64_t nMinimumInputValue; extern bool fUseFastIndex; extern unsigned int nDerivationMethodIndex; extern bool fEnforceCanonical; // Minimum disk space required - used in CheckDiskSpace() static const uint64_t nMinDiskSpace = 52428800; class CReserveKey; class CTxDB; class CTxIndex; 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_t nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* AppendBlockFile(unsigned int& nFileRet); bool LoadBlockIndex(bool fAllowNew=true); void PrintBlockTree(); CBlockIndex* FindBlockByHeight(int nHeight); bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); bool LoadExternalBlockFile(FILE* fileIn); bool FastImportBlockFile(); bool CheckProofOfWork(uint256 hash, unsigned int nBits); unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake); int64_t GetProofOfWorkReward(int64_t nFees); int64_t GetProofOfStakeReward(int64_t nCoinAge, int64_t nFees); 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); bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); uint256 WantedByOrphan(const CBlock* pblockOrphan); unsigned int LimitOrphanBlocks(unsigned int nMaxOrphans); const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); void StakeMiner(CWallet *pwallet); void ResendWalletTransactions(bool fForce = false); bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); /** Position on disk for a particular transaction. */ class CDiskTxPos { public: unsigned int nFile; unsigned int nBlockPos; unsigned int nTxPos; CDiskTxPos() { SetNull(); } CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn) { nFile = nFileIn; nBlockPos = nBlockPosIn; nTxPos = nTxPosIn; } IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) void SetNull() { nFile = (unsigned int) -1; nBlockPos = 0; nTxPos = 0; } bool IsNull() const { return (nFile == (unsigned int) -1); } friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b) { return (a.nFile == b.nFile && a.nBlockPos == b.nBlockPos && a.nTxPos == b.nTxPos); } friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b) { return !(a == b); } std::string ToString() const { if (IsNull()) return "null"; else return strprintf("(nFile=%u, nBlockPos=%u, nTxPos=%u)", nFile, nBlockPos, nTxPos); } void print() const { printf("%s", ToString().c_str()); } }; /** An inpoint - a combination of a transaction and an index n into its vin */ class CInPoint { public: CTransaction* ptx; unsigned int n; CInPoint() { SetNull(); } CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; } void SetNull() { ptx = NULL; n = (unsigned int) -1; } bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); } }; /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint { public: uint256 hash; unsigned int n; COutPoint() { SetNull(); } COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; } IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); ) void SetNull() { hash = 0; n = (unsigned int) -1; } bool IsNull() const { return (hash == 0 && n == (unsigned int) -1); } friend bool operator<(const COutPoint& a, const COutPoint& b) { return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n)); } friend bool operator==(const COutPoint& a, const COutPoint& b) { return (a.hash == b.hash && a.n == b.n); } friend bool operator!=(const COutPoint& a, const COutPoint& b) { return !(a == b); } std::string ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); } void print() const { printf("%s\n", ToString().c_str()); } }; /** An input of a transaction. It contains the location of the previous * transaction's output that it claims and a signature that matches the * output's public key. */ class CTxIn { public: COutPoint prevout; CScript scriptSig; unsigned int nSequence; CTxIn() { nSequence = std::numeric_limits::max(); } explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::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()) { prevout = COutPoint(hashPrevTx, nOut); scriptSig = scriptSigIn; nSequence = nSequenceIn; } IMPLEMENT_SERIALIZE ( READWRITE(prevout); READWRITE(scriptSig); READWRITE(nSequence); ) bool IsFinal() const { return (nSequence == std::numeric_limits::max()); } friend bool operator==(const CTxIn& a, const CTxIn& b) { return (a.prevout == b.prevout && a.scriptSig == b.scriptSig && a.nSequence == b.nSequence); } friend bool operator!=(const CTxIn& a, const CTxIn& b) { return !(a == b); } std::string ToStringShort() const { return strprintf(" %s %d", prevout.hash.ToString().c_str(), prevout.n); } std::string ToString() const { std::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); str += ")"; return str; } void print() const { printf("%s\n", ToString().c_str()); } }; /** An output of a transaction. It contains the public key that the next input * must be able to sign with to claim it. */ class CTxOut { public: int64_t nValue; CScript scriptPubKey; CTxOut() { SetNull(); } CTxOut(int64_t nValueIn, CScript scriptPubKeyIn) { nValue = nValueIn; scriptPubKey = scriptPubKeyIn; } IMPLEMENT_SERIALIZE ( READWRITE(nValue); READWRITE(scriptPubKey); ) void SetNull() { nValue = -1; scriptPubKey.clear(); } bool IsNull() { return (nValue == -1); } void SetEmpty() { nValue = 0; scriptPubKey.clear(); } bool IsEmpty() const { return (nValue == 0 && scriptPubKey.empty()); } uint256 GetHash() const { return SerializeHash(*this); } friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && a.scriptPubKey == b.scriptPubKey); } friend bool operator!=(const CTxOut& a, const CTxOut& b) { return !(a == b); } std::string ToStringShort() const { return strprintf(" out %s %s", FormatMoney(nValue).c_str(), scriptPubKey.ToString(true).c_str()); } std::string ToString() const { if (IsEmpty()) return "CTxOut(empty)"; if (scriptPubKey.size() < 6) return "CTxOut(error)"; return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().c_str()); } void print() const { printf("%s\n", ToString().c_str()); } }; enum GetMinFee_mode { GMF_BLOCK, GMF_RELAY, GMF_SEND, }; /** A single unspent transaction output entry in the UTXO database. * Keyed by (txhash, output_index). Erased when spent. */ class CUtxoEntry { public: int64_t nValue; // output value in satoshis int nHeight; // block height where output was created CScript scriptPubKey; // output script (needed for sig verification) bool fCoinBase; // from a coinbase transaction bool fCoinStake; // from a coinstake transaction unsigned int nTxTime; // transaction timestamp (needed for PoS coin age) CUtxoEntry() { SetNull(); } IMPLEMENT_SERIALIZE ( READWRITE(nValue); READWRITE(nHeight); READWRITE(scriptPubKey); READWRITE(fCoinBase); READWRITE(fCoinStake); READWRITE(nTxTime); ) void SetNull() { nValue = -1; nHeight = 0; scriptPubKey.clear(); fCoinBase = false; fCoinStake = false; nTxTime = 0; } bool IsNull() const { return (nValue == -1); } }; typedef std::map MapPrevTx; /** The basic transaction that is broadcasted on the network and contained in * blocks. A transaction can contain multiple inputs and outputs. */ class CTransaction { public: static const int CURRENT_VERSION=1; int nVersion; unsigned int nTime; std::vector vin; std::vector vout; unsigned int nLockTime; // Denial-of-service detection: mutable int nDoS; bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } CTransaction() { SetNull(); } IMPLEMENT_SERIALIZE ( READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(nTime); READWRITE(vin); READWRITE(vout); READWRITE(nLockTime); ) void SetNull() { nVersion = CTransaction::CURRENT_VERSION; nTime = GetAdjustedTime(); vin.clear(); vout.clear(); nLockTime = 0; nDoS = 0; // Denial-of-service prevention } bool IsNull() const { return (vin.empty() && vout.empty()); } uint256 GetHash() const { return SerializeHash(*this); } bool IsFinal(int nBlockHeight=0, int64_t nBlockTime=0) const { // Time based nLockTime implemented in 0.1.6 if (nLockTime == 0) return true; if (nBlockHeight == 0) nBlockHeight = nBestHeight; if (nBlockTime == 0) nBlockTime = GetAdjustedTime(); if ((int64_t)nLockTime < ((int64_t)nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) return true; for (const CTxIn& txin : vin) if (!txin.IsFinal()) return false; return true; } bool IsNewerThan(const CTransaction& old) const { if (vin.size() != old.vin.size()) return false; for (unsigned int i = 0; i < vin.size(); i++) if (vin[i].prevout != old.vin[i].prevout) return false; bool fNewer = false; unsigned int nLowest = std::numeric_limits::max(); for (unsigned int i = 0; i < vin.size(); i++) { if (vin[i].nSequence != old.vin[i].nSequence) { if (vin[i].nSequence <= nLowest) { fNewer = false; nLowest = vin[i].nSequence; } if (old.vin[i].nSequence < nLowest) { fNewer = true; nLowest = old.vin[i].nSequence; } } } return fNewer; } bool IsCoinBase() const { return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1); } bool IsCoinStake() const { // triangles: the coin stake transaction is marked with the first output empty return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); } /** Check for standard transaction types @return True if all outputs (scriptPubKeys) use only standard transaction forms */ bool IsStandard() const; /** Check for standard transaction types @param[in] mapInputs Map of previous transactions that have outputs we're spending @return True if all inputs (scriptSigs) use only standard transaction forms @see CTransaction::FetchInputs */ bool AreInputsStandard(const MapPrevTx& mapInputs) const; /** Count ECDSA signature operations the old-fashioned (pre-0.6) way @return number of sigops this transaction's outputs will produce when spent @see CTransaction::FetchInputs */ unsigned int GetLegacySigOpCount() const; /** Count ECDSA signature operations in pay-to-script-hash inputs. @param[in] mapInputs Map of previous transactions that have outputs we're spending @return maximum number of sigops required to validate this transaction's inputs @see CTransaction::FetchInputs */ unsigned int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const; /** Amount of Triangles spent by this transaction. @return sum of all outputs (note: does not include fees) */ int64_t GetValueOut() const { 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"); } return nValueOut; } /** Amount of Triangles coming in to this 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] mapInputs Map of previous transactions that have outputs we're spending @return Sum of value of all inputs (scriptSigs) @see CTransaction::FetchInputs */ int64_t GetValueIn(const MapPrevTx& mapInputs) const; int64_t GetMinFee(unsigned int nBlockSize=1, 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); if (!filein) return error("CTransaction::ReadFromDisk() : OpenBlockFile failed"); // Read transaction if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) return error("CTransaction::ReadFromDisk() : fseek failed"); try { filein >> *this; } catch (std::exception &e) { return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); } // Return file pointer if (pfileRet) { if (fseek(filein, pos.nTxPos, SEEK_SET) != 0) return error("CTransaction::ReadFromDisk() : second fseek failed"); *pfileRet = filein.release(); } return true; } friend bool operator==(const CTransaction& a, const CTransaction& b) { return (a.nVersion == b.nVersion && a.nTime == b.nTime && a.vin == b.vin && a.vout == b.vout && a.nLockTime == b.nLockTime); } friend bool operator!=(const CTransaction& a, const CTransaction& b) { return !(a == b); } std::string ToStringShort() const { std::string str; str += strprintf("%s %s", GetHash().ToString().c_str(), IsCoinBase()? "base" : (IsCoinStake()? "stake" : "user")); return str; } std::string ToString() const { std::string str; str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction"); 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, vin.size(), vout.size(), nLockTime); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) str += " " + vout[i].ToString() + "\n"; return str; } void print() const { printf("%s", ToString().c_str()); } bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet); bool ReadFromDisk(CTxDB& txdb, COutPoint prevout); bool ReadFromDisk(COutPoint prevout); bool DisconnectInputs(CTxDB& txdb); /** Fetch UTXO entries for all inputs from the UTXO database or mempool. @param[in] txdb Transaction database @param[in] mapPendingUtxos UTXOs created by earlier transactions in the same block @param[in] fBlock True if being called to add a new best-block to the chain @param[in] fMiner True if being called by CreateNewBlock @param[out] inputsRet UTXO entries for this transaction's inputs (keyed by COutPoint) @param[out] fInvalid returns true if transaction is invalid @return Returns true if all inputs are found */ bool FetchInputs(CTxDB& txdb, const MapPrevTx& mapPendingUtxos, bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid); /** Validate inputs against UTXO entries and verify signatures. @param[in] inputs UTXO entries for inputs (from FetchInputs) @param[in] pindexBlock Block being connected @param[in] fBlock true if called from ConnectBlock @param[in] fMiner true if called from CreateNewBlock @return Returns true if all checks succeed */ bool ConnectInputs(CTxDB& txdb, const MapPrevTx& inputs, const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, std::vector* pvChecks = NULL); bool ClientConnectInputs(); bool CheckTransaction() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); bool GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const; // triangles: get transaction coin age protected: const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const; }; /** A transaction with a merkle branch linking it to the block chain. */ class CMerkleTx : public CTransaction { private: int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const; public: uint256 hashBlock; std::vector vMerkleBranch; int nIndex; // memory only mutable bool fMerkleVerified; CMerkleTx() { Init(); } CMerkleTx(const CTransaction& txIn) : CTransaction(txIn) { Init(); } void Init() { hashBlock = 0; nIndex = -1; fMerkleVerified = false; } IMPLEMENT_SERIALIZE ( nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action); nVersion = this->nVersion; READWRITE(hashBlock); READWRITE(vMerkleBranch); READWRITE(nIndex); ) int SetMerkleBranch(const CBlock* pblock=NULL); // Return depth of transaction in blockchain: // -1 : not in blockchain, and not in memory pool (conflicted transaction) // 0 : in memory pool, waiting to be included in a block // >=1 : this many blocks deep in the main chain int GetDepthInMainChain(CBlockIndex* &pindexRet) const; int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); } bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; } int GetBlocksToMaturity() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true); bool AcceptToMemoryPool(); }; /** A txdb record that contains the disk location of a transaction. * Used for getrawtransaction and wallet position lookups. * vSpent is legacy (kept for serialization compat) — spent state is * tracked by the UTXO set (CUtxoEntry) since dbformat=3. */ class CTxIndex { public: CDiskTxPos pos; std::vector vSpent; CTxIndex() { SetNull(); } CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs) { pos = posIn; vSpent.resize(nOutputs); } IMPLEMENT_SERIALIZE ( if (!(nType & SER_GETHASH)) READWRITE(nVersion); READWRITE(pos); READWRITE(vSpent); ) void SetNull() { pos.SetNull(); vSpent.clear(); } bool IsNull() { return pos.IsNull(); } friend bool operator==(const CTxIndex& a, const CTxIndex& b) { return (a.pos == b.pos && a.vSpent == b.vSpent); } friend bool operator!=(const CTxIndex& a, const CTxIndex& b) { return !(a == b); } int GetDepthInMainChain() const; }; /** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work * requirements. When they solve the proof-of-work, they broadcast the block * to everyone and the block is added to the block chain. The first transaction * in the block is a special one that creates a new coin owned by the creator * of the block. * * Blocks are appended to blk0001.dat files on disk. Their location on disk * is indexed by CBlockIndex objects in memory. */ class CBlock { public: // header static const int CURRENT_VERSION=6; int nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; unsigned int nTime; unsigned int nBits; unsigned int nNonce; // network and disk std::vector vtx; // triangles: block signature - signed by one of the coin base txout[N]'s owner std::vector vchBlockSig; // memory only mutable std::vector vMerkleTree; // Denial-of-service detection: mutable int nDoS; bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } CBlock() { SetNull(); } IMPLEMENT_SERIALIZE ( READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); // ConnectBlock depends on vtx following header to generate CDiskTxPos if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY))) { READWRITE(vtx); READWRITE(vchBlockSig); } else if (fRead) { const_cast(this)->vtx.clear(); const_cast(this)->vchBlockSig.clear(); } ) void SetNull() { nVersion = CBlock::CURRENT_VERSION; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; nBits = 0; nNonce = 0; vtx.clear(); vchBlockSig.clear(); vMerkleTree.clear(); nDoS = 0; fCachedHash = false; } bool IsNull() const { return (nBits == 0); } mutable uint256 cachedHash; mutable bool fCachedHash; uint256 GetHash() const { if (!fCachedHash) { cachedHash = Hash9(BEGIN(nVersion), END(nNonce)); fCachedHash = true; } return cachedHash; } int64_t GetBlockTime() const { return (int64_t)nTime; } void UpdateTime(const CBlockIndex* pindexPrev); // triangles: entropy bit for stake modifier if chosen by modifier unsigned int GetStakeEntropyBit() const { // Take last bit of block hash as entropy bit unsigned int nEntropyBit = ((GetHash().Get64()) & 1llu); if (fDebug && GetBoolArg("-printstakemodifier")) printf("GetStakeEntropyBit: hashBlock=%s nEntropyBit=%u\n", GetHash().ToString().c_str(), nEntropyBit); return nEntropyBit; } // triangles: two types of block: proof-of-work or proof-of-stake bool IsProofOfStake() const { return (vtx.size() > 1 && vtx[1].IsCoinStake()); } bool IsProofOfWork() const { return !IsProofOfStake(); } std::pair GetProofOfStake() const { return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0); } // triangles: get max transaction timestamp int64_t GetMaxTransactionTime() const { int64_t maxTransactionTime = 0; for (const CTransaction& tx : vtx) maxTransactionTime = std::max(maxTransactionTime, (int64_t)tx.nTime); return maxTransactionTime; } uint256 BuildMerkleTree() const { vMerkleTree.clear(); for (const CTransaction& tx : vtx) vMerkleTree.push_back(tx.GetHash()); int j = 0; for (int nSize = 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]))); } j += nSize; } return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); } std::vector GetMerkleBranch(int nIndex) const { if (vMerkleTree.empty()) BuildMerkleTree(); std::vector vMerkleBranch; int j = 0; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { int i = std::min(nIndex^1, nSize-1); vMerkleBranch.push_back(vMerkleTree[j+i]); nIndex >>= 1; j += nSize; } return vMerkleBranch; } static uint256 CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) { if (nIndex == -1) return 0; for (const uint256& otherside : vMerkleBranch) { if (nIndex & 1) hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); else hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); nIndex >>= 1; } return hash; } bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet) { // Open history file to append CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION); if (!fileout) return error("CBlock::WriteToDisk() : AppendBlockFile failed"); // Write index header unsigned int nSize = fileout.GetSerializeSize(*this); fileout << FLATDATA(pchMessageStart) << nSize; // Write block long fileOutPos = ftell(fileout); if (fileOutPos < 0) return error("CBlock::WriteToDisk() : ftell failed"); nBlockPosRet = fileOutPos; fileout << *this; // Flush stdio buffers and commit to disk before returning fflush(fileout); if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) FileCommit(fileout); return true; } bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true) { SetNull(); // Open history file to read CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); if (!fReadTransactions) filein.nType |= SER_BLOCKHEADERONLY; // Read block try { filein >> *this; } catch (std::exception &e) { return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); } // Check the header if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) return error("CBlock::ReadFromDisk() : errors in block header"); return true; } void print() const { printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%" PRIszu ", vchBlockSig=%s)\n", GetHash().ToString().c_str(), nVersion, hashPrevBlock.ToString().c_str(), hashMerkleRoot.ToString().c_str(), nTime, nBits, nNonce, vtx.size(), HexStr(vchBlockSig.begin(), vchBlockSig.end()).c_str()); for (unsigned int i = 0; i < vtx.size(); i++) { printf(" "); vtx[i].print(); } printf(" vMerkleTree: "); for (unsigned int i = 0; i < vMerkleTree.size(); i++) printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str()); printf("\n"); } bool DisconnectBlock(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, const uint256& hashProofOfStake); bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true, bool fCheckSig=true) const; bool AcceptBlock(); bool GetCoinAge(uint64_t& nCoinAge) const; // triangles: calculate total coin age spent in block bool SignBlock(CWallet& keystore, int64_t nFees); bool CheckBlockSignature() const; private: bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew); }; /** The block chain is a tree shaped structure starting with the * genesis block at the root, with each block potentially having multiple * candidates to be the next block. pprev and pnext link a path through the * main/longest chain. A blockindex may have multiple pprev pointing back * to it, but pnext will only point forward to the longest branch, or will * be null if the block is not part of the longest chain. */ class CBlockIndex { public: const uint256* phashBlock; CBlockIndex* pprev; CBlockIndex* pnext; unsigned int nFile; unsigned int nBlockPos; uint256 nChainTrust; // triangles: trust score of block chain int nHeight; int64_t nMint; int64_t nMoneySupply; unsigned int nFlags; // triangles: 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 unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only // proof-of-stake specific fields COutPoint prevoutStake; unsigned int nStakeTime; uint256 hashProofOfStake; // block header int nVersion; uint256 hashMerkleRoot; unsigned int nTime; unsigned int nBits; unsigned int nNonce; CBlockIndex() { phashBlock = NULL; pprev = NULL; pnext = NULL; nFile = 0; nBlockPos = 0; nHeight = 0; nChainTrust = 0; nMint = 0; nMoneySupply = 0; nFlags = 0; nStakeModifier = 0; nStakeModifierChecksum = 0; hashProofOfStake = 0; prevoutStake.SetNull(); nStakeTime = 0; nVersion = 0; hashMerkleRoot = 0; nTime = 0; nBits = 0; nNonce = 0; } CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block) { phashBlock = NULL; pprev = NULL; pnext = NULL; nFile = nFileIn; nBlockPos = nBlockPosIn; nHeight = 0; nChainTrust = 0; nMint = 0; nMoneySupply = 0; nFlags = 0; nStakeModifier = 0; nStakeModifierChecksum = 0; hashProofOfStake = 0; if (block.IsProofOfStake()) { SetProofOfStake(); prevoutStake = block.vtx[1].vin[0].prevout; nStakeTime = block.vtx[1].nTime; } else { prevoutStake.SetNull(); nStakeTime = 0; } nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; nTime = block.nTime; nBits = block.nBits; nNonce = block.nNonce; } CBlock GetBlockHeader() const { CBlock block; block.nVersion = nVersion; if (pprev) block.hashPrevBlock = pprev->GetBlockHash(); block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; return block; } uint256 GetBlockHash() const { return *phashBlock; } int64_t GetBlockTime() const { return (int64_t)nTime; } uint256 GetBlockTrust() const; bool IsInMainChain() const { return (pnext || this == pindexBest); } bool CheckIndex() const { return true; } int64_t GetPastTimeLimit() const { return GetMedianTimePast(); } enum { nMedianTimeSpan=11 }; int64_t GetMedianTimePast() const { 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); return pbegin[(pend - pbegin)/2]; } int64_t GetMedianTime() const { const CBlockIndex* pindex = this; for (int i = 0; i < nMedianTimeSpan/2; i++) { if (!pindex->pnext) return GetBlockTime(); pindex = pindex->pnext; } 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 !(nFlags & BLOCK_PROOF_OF_STAKE); } bool IsProofOfStake() const { return (nFlags & BLOCK_PROOF_OF_STAKE); } void SetProofOfStake() { nFlags |= BLOCK_PROOF_OF_STAKE; } unsigned int GetStakeEntropyBit() const { 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); } void SetStakeModifier(uint64_t nModifier, bool fGeneratedStakeModifier) { nStakeModifier = nModifier; if (fGeneratedStakeModifier) nFlags |= BLOCK_STAKE_MODIFIER; } std::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)", pprev, pnext, nFile, nBlockPos, nHeight, FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).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 { printf("%s\n", ToString().c_str()); } }; /** Used to marshal pointers into hashes for db storage. */ class CDiskBlockIndex : public CBlockIndex { private: uint256 blockHash; public: uint256 hashPrev; uint256 hashNext; // When true, nChainTrust is included in the on-disk serialization. // Set by LoadBlockIndex based on the DB format version before deserializing. static bool fSerializeChainTrust; CDiskBlockIndex() { hashPrev = 0; hashNext = 0; blockHash = 0; } explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) { hashPrev = (pprev ? pprev->GetBlockHash() : 0); hashNext = (pnext ? pnext->GetBlockHash() : 0); } IMPLEMENT_SERIALIZE ( if (!(nType & SER_GETHASH)) READWRITE(nVersion); READWRITE(hashNext); READWRITE(nFile); READWRITE(nBlockPos); READWRITE(nHeight); READWRITE(nMint); READWRITE(nMoneySupply); 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 READWRITE(this->nVersion); READWRITE(hashPrev); READWRITE(hashMerkleRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); READWRITE(blockHash); // DB format v2+: persist chain trust to skip expensive recalculation on startup if (fSerializeChainTrust) READWRITE(nChainTrust); ) uint256 GetBlockHash() const { if (fUseFastIndex && (nTime < GetAdjustedTime() - 24 * 60 * 60) && blockHash != 0) return blockHash; CBlock block; block.nVersion = nVersion; block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; const_cast(this)->blockHash = block.GetHash(); return blockHash; } std::string ToString() const { std::string str = "CDiskBlockIndex("; str += CBlockIndex::ToString(); str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", GetBlockHash().ToString().c_str(), hashPrev.ToString().c_str(), hashNext.ToString().c_str()); return str; } void print() const { printf("%s\n", ToString().c_str()); } }; /** 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 vHave; public: CBlockLocator() { } explicit CBlockLocator(const CBlockIndex* pindex) { Set(pindex); } explicit CBlockLocator(uint256 hashBlock) { std::map::iterator mi = mapBlockIndex.find(hashBlock); if (mi != mapBlockIndex.end()) Set((*mi).second); } CBlockLocator(const std::vector& vHaveIn) { vHave = vHaveIn; } IMPLEMENT_SERIALIZE ( if (!(nType & SER_GETHASH)) READWRITE(nVersion); READWRITE(vHave); ) void SetNull() { vHave.clear(); } bool IsNull() { return vHave.empty(); } // Return the first hash in the locator (peer's tip), or 0 if empty uint256 GetTipHash() const { return vHave.empty() ? uint256(0) : vHave[0]; } void Set(const CBlockIndex* pindex) { vHave.clear(); int nStep = 1; while (pindex) { vHave.push_back(pindex->GetBlockHash()); // Exponentially larger steps back for (int i = 0; pindex && i < nStep; i++) pindex = pindex->pprev; if (vHave.size() > 10) nStep *= 2; } vHave.push_back((!fTestNet ? hashGenesisBlockOfficial : hashGenesisBlockTestNet)); } int GetDistanceBack() { // Retrace how far back it was in the sender's branch int nDistance = 0; int nStep = 1; for (const uint256& hash : vHave) { std::map::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; if (pindex->IsInMainChain()) return nDistance; } nDistance += nStep; if (nDistance > 10) nStep *= 2; } return nDistance; } CBlockIndex* GetBlockIndex() { // Find the first block the caller has in the main chain for (const uint256& hash : vHave) { std::map::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; if (pindex->IsInMainChain()) return pindex; } } return pindexGenesisBlock; } uint256 GetBlockHash() { // Find the first block the caller has in the main chain for (const uint256& hash : vHave) { std::map::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; if (pindex->IsInMainChain()) return hash; } } return (!fTestNet ? hashGenesisBlockOfficial : hashGenesisBlockTestNet); } int GetHeight() { CBlockIndex* pindex = GetBlockIndex(); if (!pindex) return 0; return pindex->nHeight; } }; class CTxMemPool { public: mutable CCriticalSection cs; std::map mapTx; std::map mapNextTx; bool accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs); bool addUnchecked(const uint256& hash, CTransaction &tx); bool remove(const CTransaction &tx, bool fRecursive = false); bool removeConflicts(const CTransaction &tx); void clear(); void queryHashes(std::vector& vtxid); unsigned long size() { LOCK(cs); return mapTx.size(); } bool exists(uint256 hash) { return (mapTx.count(hash) != 0); } CTransaction& lookup(uint256 hash) { return mapTx[hash]; } }; extern CTxMemPool mempool; extern CScriptVerifyCache scriptVerifyCache; /** * Compact block relay for Tor-only networks. * * Instead of sending a full block, send the header + short transaction IDs. * The receiver reconstructs the block from its mempool. For PoS blocks with * 0-2 transactions (the common case), the coinstake is always prefilled, so * the compact block IS the complete block — no extra round-trip needed. */ /** Short transaction ID: first 6 bytes of SipHash(txid) */ static inline uint64_t GetShortTxId(const uint256& txhash, uint64_t nonce) { // Simple short ID: XOR txhash prefix with nonce uint64_t id = 0; memcpy(&id, txhash.begin(), 6); // first 6 bytes id ^= nonce; return id & 0xFFFFFFFFFFFFULL; // mask to 48 bits } class CCompactBlock { public: // Block header fields int nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; unsigned int nTime; unsigned int nBits; unsigned int nNonce; std::vector vchBlockSig; // Compact block data uint64_t nShortIdNonce; // nonce for short ID calculation std::vector vShortTxIds; // short IDs for non-prefilled txs std::vector> vPrefilledTxn; // index + full tx CCompactBlock() : nVersion(0), nTime(0), nBits(0), nNonce(0), nShortIdNonce(0) {} // Construct from a full block: prefill coinbase + coinstake, short-ID the rest CCompactBlock(const CBlock& block) { nVersion = block.nVersion; hashPrevBlock = block.hashPrevBlock; hashMerkleRoot = block.hashMerkleRoot; nTime = block.nTime; nBits = block.nBits; nNonce = block.nNonce; vchBlockSig = block.vchBlockSig; nShortIdNonce = GetRand(std::numeric_limits::max()); for (uint16_t i = 0; i < block.vtx.size(); i++) { if (i <= 1) { // Always prefill coinbase (idx 0) and coinstake (idx 1) vPrefilledTxn.push_back(std::make_pair(i, block.vtx[i])); } else { vShortTxIds.push_back(GetShortTxId(block.vtx[i].GetHash(), nShortIdNonce)); } } } IMPLEMENT_SERIALIZE ( READWRITE(nVersion); READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); READWRITE(vchBlockSig); READWRITE(nShortIdNonce); READWRITE(vShortTxIds); READWRITE(vPrefilledTxn); ) uint256 GetBlockHash() const { CBlock hdr; hdr.nVersion = nVersion; hdr.hashPrevBlock = hashPrevBlock; hdr.hashMerkleRoot = hashMerkleRoot; hdr.nTime = nTime; hdr.nBits = nBits; hdr.nNonce = nNonce; return hdr.GetHash(); } }; class CBlockTxnRequest { public: uint256 blockhash; std::vector vIndex; // indices of missing transactions IMPLEMENT_SERIALIZE ( READWRITE(blockhash); READWRITE(vIndex); ) }; class CBlockTxnResponse { public: uint256 blockhash; std::vector vTxn; IMPLEMENT_SERIALIZE ( READWRITE(blockhash); READWRITE(vTxn); ) }; /** * Closure representing one script check for parallel verification. * Captures everything needed to call VerifyScript independently. */ class CScriptCheck { private: CScript scriptPubKey; CScript scriptSig; const CTransaction* ptxTo; unsigned int nIn; int nHashType; public: CScriptCheck() : ptxTo(NULL), nIn(0), nHashType(0) {} CScriptCheck(const CScript& scriptPubKeyIn, const CScript& scriptSigIn, const CTransaction& txToIn, unsigned int nInIn, int nHashTypeIn) : scriptPubKey(scriptPubKeyIn), scriptSig(scriptSigIn), ptxTo(&txToIn), nIn(nInIn), nHashType(nHashTypeIn) {} bool operator()() { if (!ptxTo) return false; if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nHashType)) return false; scriptVerifyCache.Set(ptxTo->GetHash(), nIn); return true; } void swap(CScriptCheck& other) { std::swap(scriptPubKey, other.scriptPubKey); std::swap(scriptSig, other.scriptSig); std::swap(ptxTo, other.ptxTo); std::swap(nIn, other.nIn); std::swap(nHashType, other.nHashType); } }; extern CCheckQueue* pScriptCheckQueue; #endif