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 unsigned int FEE_SWITCH_TIME = 1404172800; // Thu, 01 Jun 2014 00:00:00 GMT
inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
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;
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
*
* 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;
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 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