#ifndef BITCOIN_MAIN_H
#define BITCOIN_MAIN_H
+#include "timestamps.h"
#include "bignum.h"
#include "sync.h"
#include "net.h"
class CInv;
class CRequestTracker;
class CNode;
+class CBlockIndexTrustComparator;
static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
-static const int64 MIN_TX_FEE = CENT;
-static const int64 MIN_RELAY_TX_FEE = CENT;
+static const int64 MIN_TX_FEE = CENT / 10;
+static const int64 MIN_RELAY_TX_FEE = CENT / 50;
+
static const int64 MAX_MONEY = 2000000000 * COIN;
static const int64 MAX_MINT_PROOF_OF_WORK = 100 * COIN;
static const int64 MAX_MINT_PROOF_OF_STAKE = 1 * COIN;
-static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE;
-
-static const unsigned int ENTROPY_SWITCH_TIME = 1362791041; // Sat, 09 Mar 2013 01:04:01 GMT
-static const unsigned int STAKE_SWITCH_TIME = 1371686400; // Thu, 20 Jun 2013 00:00:00 GMT
-static const unsigned int TARGETS_SWITCH_TIME = 1374278400; // Sat, 20 Jul 2013 00:00:00 GMT
-static const unsigned int CHAINCHECKS_SWITCH_TIME = 1379635200; // Fri, 20 Sep 2013 00:00:00 GMT
-static const unsigned int STAKECURVE_SWITCH_TIME = 1382227200; // Sun, 20 Oct 2013 00:00:00 GMT
-static const unsigned int OUTPUT_SWITCH_TIME = 1398916800; // Thu, 01 May 2014 04:00:00 GMT
-
+static const int64 MIN_TXOUT_AMOUNT = CENT / 100;
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern std::map<uint256, CBlockIndex*> mapBlockIndex;
+extern std::set<CBlockIndex*, CBlockIndexTrustComparator> setBlockIndexValid;
extern std::set<std::pair<COutPoint, unsigned int> > setStakeSeen;
extern CBlockIndex* pindexGenesisBlock;
extern unsigned int nStakeMinAge;
extern int64 nMinimumInputValue;
extern bool fUseFastIndex;
extern unsigned int nDerivationMethodIndex;
+extern bool fEnforceCanonical;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64 nMinDiskSpace = 52428800;
class CReserveKey;
class CCoinsDB;
-class CChainDB;
+class CBlockTreeDB;
class CDiskBlockPos;
class CCoins;
class CTxUndo;
class CCoinsView;
+class CCoinsViewCache;
void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
-void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true);
+void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true);
bool ProcessBlock(CNode* pfrom, CBlock* pblock);
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake);
-int64 GetProofOfWorkReward(unsigned int nBits);
+int64 GetProofOfWorkReward(unsigned int nBits, int64 nFees=0);
int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly=false);
unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime);
bool IsInitialBlockDownload();
std::string GetWarnings(std::string strFor);
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow);
+bool SetBestChain(CBlockIndex* pindexNew);
+bool ConnectBestBlock();
+CBlockIndex * InsertBlockIndex(uint256 hash);
uint256 WantedByOrphan(const CBlock* pblockOrphan);
const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
void StakeMiner(CWallet *pwallet);
-void ResendWalletTransactions();
+void ResendWalletTransactions(bool fForce=false);
bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
return SerializeHash(*this);
}
+ uint256 GetMetaHash() const
+ {
+ return SignatureHash(CScript(), *this, 0, SIGHASH_ALL);
+ }
+
bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
{
// Time based nLockTime implemented in 0.1.6
@return True if all inputs (scriptSigs) use only standard transaction forms
@see CTransaction::FetchInputs
*/
- bool AreInputsStandard(CCoinsView& mapInputs) const;
+ bool AreInputsStandard(CCoinsViewCache& 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
@return maximum number of sigops required to validate this transaction's inputs
@see CTransaction::FetchInputs
*/
- unsigned int GetP2SHSigOpCount(CCoinsView& mapInputs) const;
+ unsigned int GetP2SHSigOpCount(CCoinsViewCache& mapInputs) const;
/** Amount of bitcoins spent by this transaction.
@return sum of all outputs (note: does not include fees)
@return Sum of value of all inputs (scriptSigs)
@see CTransaction::FetchInputs
*/
- int64 GetValueIn(CCoinsView& mapInputs) const;
+ int64 GetValueIn(CCoinsViewCache& mapInputs) const;
static bool AllowFree(double dPriority)
{
return dPriority > COIN * 144 / 250;
}
- int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK, unsigned int nBytes = 0) const;
+ int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK, unsigned int nBytes = 0, int64 nMinTxFee = MIN_TX_FEE, int64 nMinRelayTxFee = MIN_RELAY_TX_FEE) const;
friend bool operator==(const CTransaction& a, const CTransaction& b)
{
bool ClientCheckInputs() const;
// Check whether all prevouts of this transaction are present in the UTXO set represented by view
- bool HaveInputs(CCoinsView &view) const;
+ bool HaveInputs(CCoinsViewCache &view) const;
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set
- bool CheckInputs(CCoinsView &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true, CBlock *pblock=NULL) const;
+ bool CheckInputs(CCoinsViewCache &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true, CBlock *pblock=NULL) const;
// Apply the effects of this transaction on the UTXO set represented by view
- bool UpdateCoins(CCoinsView &view, CTxUndo &txundo, int nHeight, unsigned int nBlockTime) const;
+ bool UpdateCoins(CCoinsViewCache &view, CTxUndo &txundo, int nHeight, unsigned int nBlockTime, const uint256 &txhash) const;
// Context-independent validity checks
bool CheckTransaction() const;
bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
bool GetCoinAge(uint64& nCoinAge) const; // Get transaction coin age
protected:
- static CTxOut GetOutputFor(const CTxIn& input, CCoinsView& mapInputs);
+ static const CTxOut &GetOutputFor(const CTxIn& input, CCoinsViewCache& mapInputs);
};
*
* Serialized format:
* - VARINT(nVersion)
+ * - VARINT(nFlags)
* - VARINT(nCode)
* - unspentness bitvector, for vout[2] and further; least significant byte first
* - the non-spent CTxOuts (via CTxOutCompressor)
* - VARINT(nTime + is_coinstake)
* - VARINT(nBlockTime)
*
+ * The nFlag value consists of:
+ * - bit 1: is coinbase
+ * - bit 2: is coinstake
+ * - bit 3: is pruned
+ *
* The nCode value consists of:
- * - bit 1: IsCoinBase()
* - bit 2: vout[0] is not spent
* - bit 4: vout[1] is not spent
* - The higher bits encode N, the number of non-zero bytes in the following bitvector.
* - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at
* least one non-spent output).
*
- * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e40f1d75240f1d752
- * <><><--------------------------------------------><----><------><------>
- * | \ | / / /
- * version code vout[1] height timestamp block timestamp
+ * Example: 010004835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e40f1d75240f1d752
+ * <><><><--------------------------------------------><----><------><------>
+ * | | \ | / / /
+ * version | code vout[1] height timestamp block timestamp
+ * flags
*
* - version = 1
+ * - flags = 4
* - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
* - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
* - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
* * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
* - height = 203998
* - time = 1389883712
+ * - is_coinbase = 0
* - is_coinstake = 0
* - block time = 1389883712
*
*
- * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b40f1d75240f1d752
- * <><><--><--------------------------------------------------><----------------------------------------------><----><------><------>
- * / \ \ | | / / /
- * version code unspentness vout[4] vout[16] height timestamp block timestamp
+ * Example: 010508044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b40f1d75240f1d752
+ * <><><><--><--------------------------------------------------><----------------------------------------------><----><------><------>
+ * / | \ \ | | / / /
+ * version | code unspentness vout[4] vout[16] height timestamp block timestamp
+ * flags
*
* - version = 1
- * - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
+ * - flags = 5
+ * - code = 8 (neither vout[0] or vout[1] are unspent,
* 2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
* - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
* - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
* * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
* - height = 120891
* - time = 1389883712
+ * - is_coinbase = 1
* - is_coinstake = 0
* - block time = 1389883712
+ *
+ * Example: 010686af3b40f1d75240f1d752
+ * <><><----><------><------>
+ * / | \ | \
+ * version flags height timestamp block timestamp
+ *
+ * - version = 1
+ * - flags = 6 (00000110)
+ * - height = 120891
+ * - time = 1389883712
+ * - is_coinbase = 0
+ * - is_coinstake = 1
+ * - block time = 1389883712
*/
class CCoins
{
// remove spent outputs at the end of vout
void Cleanup() {
- while (vout.size() > 0 && vout.back().IsNull())
+ while (vout.size() > 0 && (vout.back().IsNull() || vout.back().IsEmpty()))
vout.pop_back();
}
unsigned int GetSerializeSize(int nType, int nVersion) const {
unsigned int nSize = 0;
- unsigned int nMaskSize = 0, nMaskCode = 0;
- CalcMaskSize(nMaskSize, nMaskCode);
- bool fFirst = vout.size() > 0 && !vout[0].IsNull();
- bool fSecond = vout.size() > 1 && !vout[1].IsNull();
- assert(fFirst || fSecond || nMaskCode);
- unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fCoinStake ? 1 : 0) + (fSecond ? 4 : 0);
+ bool fPruned = IsPruned();
+
// version
nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
- // size of header code
- nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
- // spentness bitmask
- nSize += nMaskSize;
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++)
- if (!vout[i].IsNull())
- nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
- // height
- nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
- // timestamp and coinstake flag
- nSize += ::GetSerializeSize(VARINT(nTime*2+(fCoinStake ? 1 : 0)), nType, nVersion);
- // block timestamp
- nSize += ::GetSerializeSize(VARINT(nBlockTime), nType, nVersion);
+ unsigned char nFlags = 0;
+ // coinbase, coinstake and prune flags
+ nFlags = (fCoinBase ? 1 : 0)<<0 | (fCoinStake ? 1 : 0)<<1 | (fPruned ? 1 : 0)<<2;
+ // size of flags
+ nSize += ::GetSerializeSize(VARINT(nFlags), nType, nVersion);
+
+ if (!IsPruned()) {
+ unsigned int nMaskSize = 0, nMaskCode = 0;
+ CalcMaskSize(nMaskSize, nMaskCode);
+ bool fFirst = vout.size() > 0 && !vout[0].IsNull();
+ bool fSecond = vout.size() > 1 && !vout[1].IsNull();
+
+ assert(fFirst || fSecond || nMaskCode);
+ unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+ // size of header code
+ nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
+ // spentness bitmask
+ nSize += nMaskSize;
+ // txouts themself
+ for (unsigned int i = 0; i < vout.size(); i++)
+ if (!vout[i].IsNull())
+ nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
+ // height
+ nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
+ // timestamp and coinstake flag
+ nSize += ::GetSerializeSize(VARINT(nTime), nType, nVersion);
+ // block timestamp
+ nSize += ::GetSerializeSize(VARINT(nBlockTime), nType, nVersion);
+ }
+ else {
+ // size of height
+ nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
+ // size of timestamp
+ nSize += ::GetSerializeSize(VARINT(nTime), nType, nVersion);
+ // size of block timestamp
+ nSize += ::GetSerializeSize(VARINT(nBlockTime), nType, nVersion);
+ }
+
return nSize;
}
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersion) const {
- unsigned int nMaskSize = 0, nMaskCode = 0;
- CalcMaskSize(nMaskSize, nMaskCode);
- bool fFirst = vout.size() > 0 && !vout[0].IsNull();
- bool fSecond = vout.size() > 1 && !vout[1].IsNull();
- assert(fFirst || fSecond || nMaskCode);
- unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+ bool fPruned = IsPruned();
+ unsigned char nFlags = 0;
+ nFlags = (fCoinBase ? 1 : 0)<<0 | (fCoinStake ? 1 : 0)<<1 | (fPruned ? 1 : 0)<<2;
+
// version
::Serialize(s, VARINT(this->nVersion), nType, nVersion);
- // header code
- ::Serialize(s, VARINT(nCode), nType, nVersion);
- // spentness bitmask
- for (unsigned int b = 0; b<nMaskSize; b++) {
- unsigned char chAvail = 0;
- for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
- if (!vout[2+b*8+i].IsNull())
- chAvail |= (1 << i);
- ::Serialize(s, chAvail, nType, nVersion);
+ // flags
+ ::Serialize(s, VARINT(nFlags), nType, nVersion);
+
+ if (!fPruned) {
+ unsigned int nMaskSize = 0, nMaskCode = 0;
+ CalcMaskSize(nMaskSize, nMaskCode);
+ bool fFirst = vout.size() > 0 && !vout[0].IsNull();
+ bool fSecond = vout.size() > 1 && !vout[1].IsNull();
+
+ assert(fFirst || fSecond || nMaskCode);
+
+ unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+
+ // header code
+ ::Serialize(s, VARINT(nCode), nType, nVersion);
+ // spentness bitmask
+ for (unsigned int b = 0; b<nMaskSize; b++) {
+ unsigned char chAvail = 0;
+ for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
+ if (!vout[2+b*8+i].IsNull())
+ chAvail |= (1 << i);
+ ::Serialize(s, chAvail, nType, nVersion);
+ }
+ // txouts themself
+ for (unsigned int i = 0; i < vout.size(); i++) {
+ if (!vout[i].IsNull())
+ ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
+ }
+ // coinbase height
+ ::Serialize(s, VARINT(nHeight), nType, nVersion);
+ // transaction timestamp and coinstake flag
+ ::Serialize(s, VARINT(nTime), nType, nVersion);
+ // block timestamp
+ ::Serialize(s, VARINT(nBlockTime), nType, nVersion);
}
- // txouts themself
- for (unsigned int i = 0; i < vout.size(); i++) {
- if (!vout[i].IsNull())
- ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
+ else {
+ // coinbase height
+ ::Serialize(s, VARINT(nHeight), nType, nVersion);
+ // transaction timestamp
+ ::Serialize(s, VARINT(nTime), nType, nVersion);
+ // block timestamp
+ ::Serialize(s, VARINT(nBlockTime), nType, nVersion);
}
- // coinbase height
- ::Serialize(s, VARINT(nHeight), nType, nVersion);
- // transaction timestamp and coinstake flag
- ::Serialize(s, VARINT(nTime*2+(fCoinStake ? 1 : 0)), nType, nVersion);
- // block time
- ::Serialize(s, VARINT(nBlockTime), nType, nVersion);
}
template<typename Stream>
void Unserialize(Stream &s, int nType, int nVersion) {
- unsigned int nCode = 0, nCodeTime = 0;
+ unsigned char nFlags = 0;
+
// version
::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
- // header code
- ::Unserialize(s, VARINT(nCode), nType, nVersion);
- fCoinBase = nCode & 1;
- std::vector<bool> vAvail(2, false);
- vAvail[0] = nCode & 2;
- vAvail[1] = nCode & 4;
- unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
- // spentness bitmask
- while (nMaskCode > 0) {
- unsigned char chAvail = 0;
- ::Unserialize(s, chAvail, nType, nVersion);
- for (unsigned int p = 0; p < 8; p++) {
- bool f = (chAvail & (1 << p)) != 0;
- vAvail.push_back(f);
+ // coinbase and coinstake flags
+ ::Unserialize(s, VARINT(nFlags), nType, nVersion);
+
+ fCoinBase = nFlags & (1<<0);
+ fCoinStake = nFlags & (1<<1);
+ bool fPruned = nFlags & (1<<2);
+
+ if (!fPruned) {
+ unsigned int nCode = 0;
+ // header code
+ ::Unserialize(s, VARINT(nCode), nType, nVersion);
+ std::vector<bool> vAvail(2, false);
+ vAvail[0] = nCode & 2;
+ vAvail[1] = nCode & 4;
+ unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
+ // spentness bitmask
+ while (nMaskCode > 0) {
+ unsigned char chAvail = 0;
+ ::Unserialize(s, chAvail, nType, nVersion);
+ for (unsigned int p = 0; p < 8; p++) {
+ bool f = (chAvail & (1 << p)) != 0;
+ vAvail.push_back(f);
+ }
+ if (chAvail != 0)
+ nMaskCode--;
+ }
+ // txouts themself
+ vout.assign(vAvail.size(), CTxOut());
+ for (unsigned int i = 0; i < vAvail.size(); i++) {
+ if (vAvail[i])
+ ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
}
- if (chAvail != 0)
- nMaskCode--;
+ // coinbase height
+ ::Unserialize(s, VARINT(nHeight), nType, nVersion);
+ // transaction timestamp
+ ::Unserialize(s, VARINT(nTime), nType, nVersion);
+ nTime = nTime;
+ // block timestamp
+ ::Unserialize(s, VARINT(nBlockTime), nType, nVersion);
}
- // txouts themself
- vout.assign(vAvail.size(), CTxOut());
- for (unsigned int i = 0; i < vAvail.size(); i++) {
- if (vAvail[i])
- ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
+ else {
+ // coinbase height
+ ::Unserialize(s, VARINT(nHeight), nType, nVersion);
+ // transaction timestamp
+ ::Unserialize(s, VARINT(nTime), nType, nVersion);
+ // block timestamp
+ ::Unserialize(s, VARINT(nBlockTime), nType, nVersion);
}
- // coinbase height
- ::Unserialize(s, VARINT(nHeight), nType, nVersion);
- // transaction timestamp
- ::Unserialize(s, VARINT(nCodeTime), nType, nVersion);
- nTime = nCodeTime / 2;
- fCoinStake = nCodeTime & 1;
- // block timestamp
- ::Unserialize(s, VARINT(nBlockTime), nType, nVersion);
Cleanup();
}
// check whether the entire CCoins is spent
// note that only !IsPruned() CCoins can be serialized
bool IsPruned() const {
+ if (vout.size() == 0)
+ return true;
+
BOOST_FOREACH(const CTxOut &out, vout)
if (!out.IsNull())
return false;
+
return true;
}
};
void UpdateTime(const CBlockIndex* pindexPrev);
- // ppcoin: entropy bit for stake modifier if chosen by modifier
- unsigned int GetStakeEntropyBit(unsigned int nTime) const
- {
- // Protocol switch to support p2pool at novacoin block #9689
- if (nTime >= ENTROPY_SWITCH_TIME || fTestNet)
- {
- // Take last bit of block hash as entropy bit
- unsigned int nEntropyBit = ((GetHash().Get64()) & 1llu);
- if (fDebug && GetBoolArg("-printstakemodifier"))
- printf("GetStakeEntropyBit: nTime=%u hashBlock=%s nEntropyBit=%u\n", nTime, GetHash().ToString().c_str(), nEntropyBit);
- return nEntropyBit;
- }
- // Before novacoin block #9689 - old protocol
- uint160 hashSig = Hash160(vchBlockSig);
- if (fDebug && GetBoolArg("-printstakemodifier"))
- printf("GetStakeEntropyBit: hashSig=%s", hashSig.ToString().c_str());
- hashSig >>= 159; // take the first bit of the hash
- if (fDebug && GetBoolArg("-printstakemodifier"))
- printf(" entropybit=%"PRI64d"\n", hashSig.Get64());
- return hashSig.Get64();
- }
+ unsigned int GetStakeEntropyBit(unsigned int nTime) const;
- // ppcoin: two types of block: proof-of-work or proof-of-stake
+ // two types of block: proof-of-work or proof-of-stake
bool IsProofOfStake() const
{
return (vtx.size() > 1 && vtx[1].IsCoinStake());
return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0);
}
- // ppcoin: get max transaction timestamp
+ // get max transaction timestamp
int64 GetMaxTransactionTime() const
{
int64 maxTransactionTime = 0;
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}
+ const uint256 &GetTxHash(unsigned int nIndex) const {
+ assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
+ assert(nIndex < vtx.size());
+ return vMerkleTree[nIndex];
+ }
+
std::vector<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
}
// Undo the effects of this block (with given index) on the UTXO set represented by coins
- bool DisconnectBlock(CBlockIndex *pindex, CCoinsView &coins);
+ bool DisconnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins);
// Apply the effects of this block (with given index) on the UTXO set represented by coins
- bool ConnectBlock(CBlockIndex *pindex, CCoinsView &coins, bool fJustCheck=false);
+ bool ConnectBlock(CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false);
// Read a block from disk
bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
- // Make this block (with given index) the new tip of the active block chain
- bool SetBestChain(CBlockIndex* pindexNew);
-
// Add this block to the block index, and if necessary, switch the active block chain to this
bool AddToBlockIndex(const CDiskBlockPos &pos);
// Context-independent validity checks
+ bool CheckBlockHeader(bool fCheckPoW=true, bool fCheckSig=false) const;
bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true, bool fCheckSig=false) const;
// Store block on disk
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
+ BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint
+ BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root
+ BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30
+ BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok
+ BLOCK_VALID_MASK = 7,
+
+ BLOCK_HAVE_DATA = 8, // full block available in blk*.dat
+ BLOCK_HAVE_UNDO = 16, // undo data available in rev*.dat
+ BLOCK_HAVE_MASK = 24,
+
+ BLOCK_FAILED_VALID = 32, // stage after last reached validness failed
+ BLOCK_FAILED_CHILD = 64, // descends from failed block
+ BLOCK_FAILED_MASK = 96
+};
+
/** 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
class CBlockIndex
{
public:
+ // pointer to the hash of the block, if any. memory is owned by this CBlockIndex
const uint256* phashBlock;
+
+ // pointer to the index of the predecessor of this block
CBlockIndex* pprev;
+
+ // (memory only) pointer to the index of the *active* successor of this block
CBlockIndex* pnext;
+
+ // height of the entry in the chain. The genesis block has height 0
int nHeight;
- CDiskBlockPos pos;
+
+ // Which # file this block is stored in (blk?????.dat)
+ int nFile;
+
+ // Byte offset within blk?????.dat where this block's data is stored
+ unsigned int nDataPos;
+
+ // Byte offset within rev?????.dat where this block's undo data is stored
unsigned int nUndoPos;
- uint256 nChainTrust; // trust score of block chain
+ // (memory only) Trust score of block chain up to and including this block
+ uint256 nChainTrust;
+
+ // Number of transactions in this block.
+ unsigned int nTx;
+
+ // (memory only) Number of transactions in the chain up to and including this block
+ unsigned int nChainTx;
+
+ // Verification status of this block. See enum BlockStatus for detailed info
+ unsigned int nStatus;
+
+ // Coins amount created by this block
int64 nMint;
+
+ // Total coins created in this block chain up to and including this block
int64 nMoneySupply;
+ // Block flags
unsigned int nFlags;
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
+ // is proof-of-stake block
+ BLOCK_PROOF_OF_STAKE = (1 << 0),
+ // entropy bit for stake modifier
+ BLOCK_STAKE_ENTROPY = (1 << 1),
+ // regenerated stake modifier
+ BLOCK_STAKE_MODIFIER = (1 << 2),
};
- uint64 nStakeModifier; // hash modifier for proof-of-stake
- unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only
+ // Hash modifier for proof-of-stake kernel
+ uint64 nStakeModifier;
+
+ // Checksum of index in-memory only
+ unsigned int nStakeModifierChecksum;
- // proof-of-stake specific fields
+ // Predecessor of coinstake transaction
COutPoint prevoutStake;
+
+ // Timestamp of coinstake transaction
unsigned int nStakeTime;
+
+ // Kernel hash
uint256 hashProofOfStake;
- // block header
+ // Block header
int nVersion;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
-
CBlockIndex()
{
phashBlock = NULL;
pprev = NULL;
pnext = NULL;
nHeight = 0;
- pos.SetNull();
+ nFile = 0;
+ nDataPos = 0;
nUndoPos = 0;
nChainTrust = 0;
+ nTx = 0;
+ nChainTx = 0;
+ nStatus = 0;
nMint = 0;
nMoneySupply = 0;
nFlags = 0;
pprev = NULL;
pnext = NULL;
nHeight = 0;
- pos.SetNull();
+ nFile = 0;
+ nDataPos = 0;
nUndoPos = 0;
nChainTrust = 0;
+ nTx = 0;
+ nChainTx = 0;
+ nStatus = 0;
nMint = 0;
nMoneySupply = 0;
nFlags = 0;
}
CDiskBlockPos GetBlockPos() const {
- return pos;
+ CDiskBlockPos ret;
+ if (nStatus & BLOCK_HAVE_DATA) {
+ ret.nFile = nFile;
+ ret.nPos = nDataPos;
+ } else
+ ret.SetNull();
+ return ret;
}
CDiskBlockPos GetUndoPos() const {
- CDiskBlockPos ret = pos;
- if (nUndoPos == 0)
+ CDiskBlockPos ret;
+ if (nStatus & BLOCK_HAVE_UNDO) {
+ ret.nFile = nFile;
+ ret.nPos = nUndoPos;
+ } else
ret.SetNull();
- else
- ret.nPos = nUndoPos - 1;
return ret;
}
}
};
+struct CBlockIndexTrustComparator
+{
+ bool operator()(CBlockIndex *pa, CBlockIndex *pb) {
+ if (pa->nChainTrust > pb->nChainTrust) return false;
+ if (pa->nChainTrust < pb->nChainTrust) return true;
+
+ return false; // identical blocks
+ }
+};
+
/** Used to marshal pointers into hashes for db storage. */
class CDiskBlockIndex : public CBlockIndex
{
IMPLEMENT_SERIALIZE
(
if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
-
- READWRITE(nHeight);
- READWRITE(pos);
- READWRITE(nUndoPos);
+ READWRITE(VARINT(nVersion));
+
+ READWRITE(VARINT(nHeight));
+ READWRITE(VARINT(nStatus));
+ READWRITE(VARINT(nTx));
+ if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
+ READWRITE(VARINT(nFile));
+ if (nStatus & BLOCK_HAVE_DATA)
+ READWRITE(VARINT(nDataPos));
+ if (nStatus & BLOCK_HAVE_UNDO)
+ READWRITE(VARINT(nUndoPos));
READWRITE(nMint);
READWRITE(nMoneySupply);
READWRITE(nFlags);
extern CTxMemPool mempool;
+struct CCoinsStats
+{
+ int nHeight;
+ uint64 nTransactions;
+ uint64 nPrunedTransactions;
+ uint64 nTransactionOutputs;
+ uint64 nSerializedSize;
+
+ CCoinsStats() : nHeight(0), nTransactions(0), nPrunedTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {}
+};
+
/** Abstract view on the open txout dataset. */
class CCoinsView
{
// Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex);
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ virtual bool GetStats(CCoinsStats &stats);
};
/** CCoinsView backed by another CCoinsView */
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 */
bool GetCoinsReadOnly(uint256 txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins);
bool HaveCoins(uint256 txid);
+ CCoins &GetCoins(uint256 txid);
CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
bool Flush();
unsigned int GetCacheSize();
+private:
+ std::map<uint256,CCoins>::iterator FetchCoins(uint256 txid);
};
/** CCoinsView that brings transactions from a memorypool into view.
bool HaveCoins(uint256 txid);
};
+/** Global variable that points to the active CCoinsView (protected by cs_main) */
extern CCoinsViewCache *pcoinsTip;
+/** Global variable that points to the active block tree (protected by cs_main) */
+extern CBlockTreeDB *pblocktree;
+
#endif